From dee579ea2ab68f14d06554f131a2a81b27b7503d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Mar 2014 17:05:59 +0100 Subject: [PATCH] The sbuf allocation cleanups This is an attempt to fix the nonoptimal memory allocations. The old code tries to allocate new chunks based on maximum packet value, but the streams contain mostly short chunks. Also, in some cases, we know the fixed sbuf size, so use it. --- src/input/mpegts/mpegts_service.c | 3 ++ src/input/mpegts/tsdemux.c | 5 ++- src/parsers/parsers.c | 23 ++++------ src/tvheadend.h | 25 +++++++++-- src/utils.c | 71 ++++++++++++++++++++----------- 5 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index efab8419..76391338 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -241,6 +241,9 @@ mpegts_service_stop(service_t *t) /* Stop */ if (i) i->mi_close_service(i, s); + + /* Save some memory */ + sbuf_free(&s->s_tsbuf); } /* diff --git a/src/input/mpegts/tsdemux.c b/src/input/mpegts/tsdemux.c index 7cb078d1..d9b7ee4d 100644 --- a/src/input/mpegts/tsdemux.c +++ b/src/input/mpegts/tsdemux.c @@ -297,6 +297,9 @@ ts_remux(mpegts_service_t *t, const uint8_t *src) pktbuf_t *pb; sbuf_t *sb = &t->s_tsbuf; + if (sb->sb_data == NULL) + sbuf_init_fixed(sb, TS_REMUX_BUFSIZE); + sbuf_append(sb, src, 188); if(sb->sb_ptr < TS_REMUX_BUFSIZE) @@ -312,7 +315,7 @@ ts_remux(mpegts_service_t *t, const uint8_t *src) service_set_streaming_status_flags((service_t*)t, TSS_PACKETS); - sbuf_reset(sb); + sbuf_reset(sb, TS_REMUX_BUFSIZE); } /* diff --git a/src/parsers/parsers.c b/src/parsers/parsers.c index c3f21803..8ff6e4e1 100644 --- a/src/parsers/parsers.c +++ b/src/parsers/parsers.c @@ -231,7 +231,7 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data, /* Payload unit start */ st->es_parser_state = 1; st->es_parser_ptr = 0; - sbuf_reset(&st->es_buf); + sbuf_reset(&st->es_buf, 4000); } if(st->es_parser_state == 0) @@ -351,9 +351,9 @@ parse_sc(service_t *t, elementary_stream_t *st, const uint8_t *data, int len, r = 1; } - assert(st->es_buf.sb_data != NULL); - if(r == 2) { + assert(st->es_buf.sb_data != NULL); + // Drop packet st->es_buf.sb_ptr = st->es_startcode_offset; @@ -367,12 +367,13 @@ parse_sc(service_t *t, elementary_stream_t *st, const uint8_t *data, int len, if(r == 1) { /* Reset packet parser upon length error or if parser tells us so */ - sbuf_reset(&st->es_buf); + sbuf_reset_and_alloc(&st->es_buf, 256); st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 24; st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 16; st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc >> 8; st->es_buf.sb_data[st->es_buf.sb_ptr++] = sc; } + assert(st->es_buf.sb_data != NULL); st->es_startcode = sc; st->es_startcode_offset = st->es_buf.sb_ptr - 4; } @@ -1118,17 +1119,11 @@ parse_mpeg2video(service_t *t, elementary_stream_t *st, size_t len, pkt->pkt_payload = pktbuf_make(st->es_buf.sb_data, st->es_buf.sb_ptr - 4); pkt->pkt_duration = st->es_frame_duration; + sbuf_steal_data(&st->es_buf); parser_deliver(t, st, pkt, st->es_buf.sb_err); st->es_curpkt = NULL; - st->es_buf.sb_data = malloc(st->es_buf.sb_size); - if(st->es_buf.sb_data == NULL) { - fprintf(stderr, "Unable to allocate %d bytes\n", - st->es_buf.sb_size); - abort(); - } - return 1; } break; @@ -1248,10 +1243,10 @@ parse_h264(service_t *t, elementary_stream_t *st, size_t len, pkt->pkt_payload = pktbuf_make(st->es_buf.sb_data, st->es_buf.sb_ptr - 4); + sbuf_steal_data(&st->es_buf); parser_deliver(t, st, pkt, st->es_buf.sb_err); st->es_curpkt = NULL; - st->es_buf.sb_data = malloc(st->es_buf.sb_size); st->es_curdts = PTS_UNSET; st->es_curpts = PTS_UNSET; @@ -1276,7 +1271,7 @@ parse_subtitles(service_t *t, elementary_stream_t *st, const uint8_t *data, if(start) { /* Payload unit start */ st->es_parser_state = 1; - sbuf_reset(&st->es_buf); + sbuf_reset(&st->es_buf, 4000); } if(st->es_parser_state == 0) @@ -1339,7 +1334,7 @@ parse_teletext(service_t *t, elementary_stream_t *st, const uint8_t *data, if(start) { st->es_parser_state = 1; st->es_parser_ptr = 0; - sbuf_reset(&st->es_buf); + sbuf_reset(&st->es_buf, 4000); } if(st->es_parser_state == 0) diff --git a/src/tvheadend.h b/src/tvheadend.h index 34b5cf13..ace8a63e 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -583,13 +583,32 @@ static inline int64_t ts_rescale_i(int64_t ts, int tb) void sbuf_init(sbuf_t *sb); +void sbuf_init_fixed(sbuf_t *sb, int len); + void sbuf_free(sbuf_t *sb); -void sbuf_reset(sbuf_t *sb); +void sbuf_reset(sbuf_t *sb, int max_len); -void sbuf_err(sbuf_t *sb); +void sbuf_reset_and_alloc(sbuf_t *sb, int len); -void sbuf_alloc(sbuf_t *sb, int len); +static inline void sbuf_steal_data(sbuf_t *sb) +{ + sb->sb_data = NULL; + sb->sb_ptr = sb->sb_size = 0; +} + +static inline void sbuf_err(sbuf_t *sb) +{ + sb->sb_err = 1; +} + +void sbuf_alloc_(sbuf_t *sb, int len); + +static inline void sbuf_alloc(sbuf_t *sb, int len) +{ + if (sb->sb_ptr + len >= sb->sb_size) + sbuf_alloc_(sb, len); +} void sbuf_append(sbuf_t *sb, const void *data, int len); diff --git a/src/utils.c b/src/utils.c index 57bcbe2b..69f51c28 100644 --- a/src/utils.c +++ b/src/utils.c @@ -247,6 +247,12 @@ put_utf8(char *out, int c) return 6; } +static void +sbuf_alloc_fail(int len) +{ + fprintf(stderr, "Unable to allocate %d bytes\n", len); + abort(); +} void sbuf_init(sbuf_t *sb) @@ -254,62 +260,77 @@ sbuf_init(sbuf_t *sb) memset(sb, 0, sizeof(sbuf_t)); } +void +sbuf_init_fixed(sbuf_t *sb, int len) +{ + memset(sb, 0, sizeof(sbuf_t)); + sb->sb_data = malloc(len); + if (sb->sb_data == NULL) + sbuf_alloc_fail(len); + sb->sb_size = len; +} void sbuf_free(sbuf_t *sb) { - if(sb->sb_data) - free(sb->sb_data); + free(sb->sb_data); sb->sb_size = sb->sb_ptr = sb->sb_err = 0; sb->sb_data = NULL; } void -sbuf_reset(sbuf_t *sb) +sbuf_reset(sbuf_t *sb, int max_len) { - sb->sb_ptr = 0; - sb->sb_err = 0; + sb->sb_ptr = sb->sb_err = 0; + if (sb->sb_size > max_len) { + void *n = realloc(sb->sb_data, max_len); + if (n) { + sb->sb_data = n; + sb->sb_size = max_len; + } + } } void -sbuf_err(sbuf_t *sb) +sbuf_reset_and_alloc(sbuf_t *sb, int len) { - sb->sb_err = 1; + if (sb->sb_data) { + if (len != sb->sb_size) { + void *n = realloc(sb->sb_data, len); + if (n) { + sb->sb_data = n; + sb->sb_size = len; + } + } + } else { + sb->sb_data = malloc(len); + sb->sb_size = len; + } + if (sb->sb_data == NULL) + sbuf_alloc_fail(len); + sb->sb_ptr = sb->sb_err = 0; } void -sbuf_alloc(sbuf_t *sb, int len) +sbuf_alloc_(sbuf_t *sb, int len) { if(sb->sb_data == NULL) { sb->sb_size = len * 4 > 4000 ? len * 4 : 4000; sb->sb_data = malloc(sb->sb_size); return; - } - - if(sb->sb_ptr + len >= sb->sb_size) { + } else { sb->sb_size += len * 4; sb->sb_data = realloc(sb->sb_data, sb->sb_size); } -} -static void -sbuf_alloc1(sbuf_t *sb, int len) -{ - if(sb->sb_data == NULL) { - sb->sb_size = len * 4 > 4000 ? len * 4 : 4000; - sb->sb_data = malloc(sb->sb_size); - return; - } - - sb->sb_size += len * 4; - sb->sb_data = realloc(sb->sb_data, sb->sb_size); + if(sb->sb_data == NULL) + sbuf_alloc_fail(sb->sb_size); } void sbuf_append(sbuf_t *sb, const void *data, int len) { - if(sb->sb_ptr + len >= sb->sb_size) - sbuf_alloc1(sb, len); + sbuf_alloc(sb, len); memcpy(sb->sb_data + sb->sb_ptr, data, len); sb->sb_ptr += len; }