From: Andreas Ă–man Date: Sat, 29 Oct 2011 21:01:02 +0000 (+0200) Subject: Correctly multiplex h264 in MKV X-Git-Tag: 2.99~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb106fa1df2745d5f1068576158e990192ab3d3b;p=thirdparty%2Ftvheadend.git Correctly multiplex h264 in MKV Patch by patrick boissonade Some adaption (drop dep on libav) by andoma --- diff --git a/Makefile b/Makefile index 20012a265..0dcad36d4 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ SRCS = src/main.c \ src/htsstr.c \ src/rawtsinput.c \ src/iptv_input.c \ + src/avc.c \ SRCS += src/plumbing/tsfix.c \ diff --git a/src/avc.c b/src/avc.c index 4418de772..afad9e4a9 100644 --- a/src/avc.c +++ b/src/avc.c @@ -21,87 +21,65 @@ #include "avc.h" -const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end) +static const uint8_t * +avc_find_startcode(const uint8_t *p, const uint8_t *end) { - const uint8_t *a = p + 4 - ((long)p & 3); - - for( end -= 3; p < a && p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; - } - - for( end -= 3; p < end; p += 4 ) { - uint32_t x = *(const uint32_t*)p; -// if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian -// if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian - if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic - if( p[1] == 0 ) { - if( p[0] == 0 && p[2] == 1 ) - return p-1; - if( p[2] == 0 && p[3] == 1 ) - return p; - } - if( p[3] == 0 ) { - if( p[2] == 0 && p[4] == 1 ) - return p+1; - if( p[4] == 0 && p[5] == 1 ) - return p+2; - } - } - } - - for( end += 3; p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; + int i; + + uint32_t sc=0xFFFFFFFF; + size_t len = (end -p)+1; + for (i=0;i 3 && !(b[l-3] | b[l-2] | b[l-1])) - l--; - put_be32(pb, l); - put_buffer(pb, nal_start, l); - size += 4 + l; - nal_start = nal_end; + const uint8_t *p = buf_in; + const uint8_t *end = p + size; + const uint8_t *nal_start, *nal_end; + + //printf("CONVERT SIZE %d\n", size); + + size = 0; + nal_start = avc_find_startcode(p, end); + while (nal_start < end) { + while(!*(nal_start++)); + nal_end = avc_find_startcode(nal_start, end); + /*printf("%4d bytes %5d : %d\n", nal_end - nal_start, + nal_start - buf_in, + nal_end - buf_in);*/ + + int l = nal_end - nal_start; + + if (l) { + sbuf_put_be32(sb, l); + sbuf_append(sb, nal_start, l); + size += 4 + l; } - printf("size=%d\n", size); - return size; + nal_start = nal_end; + } + return size; } -int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) +static int +avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) { - ByteIOContext *pb; - int ret = url_open_dyn_buf(&pb); - if(ret < 0) - return ret; - - avc_parse_nal_units(pb, buf_in, *size); - - av_freep(buf); - *size = url_close_dyn_buf(pb, buf); - return 0; + sbuf_t sb; + sbuf_init(&sb); + avc_parse_nal_units(&sb, buf_in, *size); + + free(*buf); + *buf = sb.sb_data; + *size = sb.sb_ptr; + return 0; } @@ -118,60 +96,82 @@ RB24(const uint8_t *d) } -static int isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len) +static int +isom_write_avcc(sbuf_t *sb, const uint8_t *data, int len) { - if (len > 6) { - /* check for h264 start code */ - if (RB32(data) == 0x00000001 || - RB24(data) == 0x000001) { - uint8_t *buf=NULL, *end, *start; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; - - int ret = avc_parse_nal_units_buf(data, &buf, &len); - if (ret < 0) - return ret; - start = buf; - end = buf + len; - - /* look for sps and pps */ - while (buf < end) { - unsigned int size; - uint8_t nal_type; - size = RB32(buf); - nal_type = buf[4] & 0x1f; - if (nal_type == 7) { /* SPS */ - sps = buf + 4; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf + 4; - pps_size = size; - } - buf += size + 4; - } - if(!sps || !pps) { - av_free(start); - return -1; - } - - put_byte(pb, 1); /* version */ - put_byte(pb, sps[1]); /* profile */ - put_byte(pb, sps[2]); /* profile compat */ - put_byte(pb, sps[3]); /* level */ - put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - put_be16(pb, sps_size); - put_buffer(pb, sps, sps_size); - put_byte(pb, 1); /* number of pps */ - put_be16(pb, pps_size); - put_buffer(pb, pps, pps_size); - av_free(start); - } else { - put_buffer(pb, data, len); - } + if (len > 6) { + /* check for h264 start code */ + if (RB32(data) == 0x00000001 || + RB24(data) == 0x000001) { + uint8_t *buf=NULL, *end, *start; + uint32_t *sps_size_array=0, *pps_size_array=0; + uint32_t pps_count=0,sps_count=0; + uint8_t **sps_array=0, **pps_array=0; + int i; + + int ret = avc_parse_nal_units_buf(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + /* look for sps and pps */ + while (buf < end) { + unsigned int size; + uint8_t nal_type; + size = RB32(buf); + nal_type = buf[4] & 0x1f; + if (nal_type == 7) { /* SPS */ + sps_array = realloc(sps_array,sizeof(uint8_t*)*(sps_count+1)); + sps_size_array = realloc(sps_size_array,sizeof(uint32_t)*(sps_count+1)); + sps_array[sps_count] = buf + 4; + sps_size_array[sps_count] = size; + sps_count++; + } else if (nal_type == 8) { /* PPS */ + pps_size_array = realloc(pps_size_array,sizeof(uint32_t)*(pps_count+1)); + pps_array = realloc(pps_array,sizeof (uint8_t*)*(pps_count+1)); + pps_array[pps_count] = buf + 4; + pps_size_array[pps_count] = size; + pps_count++; + } + buf += size + 4; + } + if(!sps_count || !pps_count) { + free(start); + if (sps_count) + free(sps_array); + if (pps_count) + free(pps_array); + return -1; + } + + sbuf_put_byte(sb, 1); /* version */ + sbuf_put_byte(sb, sps_array[0][1]); /* profile */ + sbuf_put_byte(sb, sps_array[0][2]); /* profile compat */ + sbuf_put_byte(sb, sps_array[0][3]); /* level */ + sbuf_put_byte(sb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + sbuf_put_byte(sb, 0xe0+sps_count); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ + for (i=0;ipkt_refcount = 1; + pkt->pkt_header = NULL; + pkt->pkt_payload = NULL; + + pkt->pkt_payload = malloc(sizeof(pktbuf_t)); + pkt->pkt_payload->pb_refcount=1; + if (src->pkt_header) { + sbuf_t headers; + sbuf_init(&headers); + + isom_write_avcc(&headers, pktbuf_ptr(src->pkt_header), + pktbuf_len(src->pkt_header)); + pkt->pkt_header = pktbuf_make(headers.sb_data, headers.sb_ptr); + } - url_open_dyn_buf(&payload); - avc_parse_nal_units(payload, pkt->pkt_payload, pkt->pkt_payloadlen); - - pkt->pkt_payloadlen = url_close_dyn_buf(payload, &pkt->pkt_payload); - - if(pkt->pkt_globaldata) { - url_open_dyn_buf(&headers); - - isom_write_avcc(headers, pkt->pkt_globaldata, pkt->pkt_globaldata_len); - pkt->pkt_globaldata_len = url_close_dyn_buf(headers, &pkt->pkt_globaldata); - - hexdump("annexB: ", src->pkt_globaldata, src->pkt_globaldata_len); - hexdump(" AVC: ", pkt->pkt_globaldata, pkt->pkt_globaldata_len); + sbuf_t payload; + sbuf_init(&payload); + if(src->pkt_header) + avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_header), + pktbuf_len(src->pkt_header)); - } + avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_payload), + pktbuf_len(src->pkt_payload)); + + pkt->pkt_payload = pktbuf_make(payload.sb_data, payload.sb_ptr); pkt_ref_dec(src); return pkt; } diff --git a/src/avc.h b/src/avc.h index 5b8c1ea26..631d0d4c7 100644 --- a/src/avc.h +++ b/src/avc.h @@ -22,16 +22,9 @@ #ifndef AVC_H__ #define AVC_H__ -#include -#include -#include -#include "tvhead.h" +#include "tvheadend.h" #include "packet.h" -const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end); -int avc_parse_nal_units(ByteIOContext *pb, const uint8_t *buf_in, int size); -int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size); th_pkt_t *avc_convert_pkt(th_pkt_t *src); - #endif diff --git a/src/plumbing/globalheaders.c b/src/plumbing/globalheaders.c index 703591bd3..7eff555cf 100644 --- a/src/plumbing/globalheaders.c +++ b/src/plumbing/globalheaders.c @@ -20,6 +20,7 @@ #include "tvheadend.h" #include "streaming.h" #include "globalheaders.h" +#include "avc.h" typedef struct globalheaders { streaming_target_t gh_input; @@ -164,7 +165,7 @@ convertpkt(streaming_start_component_t *ssc, th_pkt_t *pkt) { switch(ssc->ssc_type) { case SCT_H264: - // return avc_convert_pkt(pkt); + return avc_convert_pkt(pkt); default: return pkt; diff --git a/src/tvheadend.h b/src/tvheadend.h index e1a4e4d04..2fb798046 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -428,6 +428,8 @@ static inline int64_t ts_rescale(int64_t ts, int tb) return (ts * tb ) / 90000LL; } +void sbuf_init(sbuf_t *sb); + void sbuf_free(sbuf_t *sb); void sbuf_reset(sbuf_t *sb); diff --git a/src/utils.c b/src/utils.c index 65a2de2f8..5b792d665 100644 --- a/src/utils.c +++ b/src/utils.c @@ -227,6 +227,12 @@ put_utf8(char *out, int c) } +void +sbuf_init(sbuf_t *sb) +{ + memset(sb, 0, sizeof(sbuf_t)); +} + void sbuf_free(sbuf_t *sb)