diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/h264.c | 179 | ||||
-rw-r--r-- | src/srcs.mk | 1 |
2 files changed, 180 insertions, 0 deletions
diff --git a/src/h264.c b/src/h264.c new file mode 100644 index 0000000..8da811d --- /dev/null +++ b/src/h264.c @@ -0,0 +1,179 @@ +/** + * @file src/h264.c H.264 video codec packetization (RFC 3984) + * + * Copyright (C) 2010 - 2015 Creytiv.com + */ +#include <string.h> +#include <re.h> +#include <rem.h> +#include <baresip.h> + + +int h264_hdr_encode(const struct h264_hdr *hdr, struct mbuf *mb) +{ + uint8_t v; + + v = hdr->f<<7 | hdr->nri<<5 | hdr->type<<0; + + return mbuf_write_u8(mb, v); +} + + +int h264_hdr_decode(struct h264_hdr *hdr, struct mbuf *mb) +{ + uint8_t v; + + if (mbuf_get_left(mb) < 1) + return ENOENT; + + v = mbuf_read_u8(mb); + + hdr->f = v>>7 & 0x1; + hdr->nri = v>>5 & 0x3; + hdr->type = v>>0 & 0x1f; + + return 0; +} + + +int h264_fu_hdr_encode(const struct h264_fu *fu, struct mbuf *mb) +{ + uint8_t v = fu->s<<7 | fu->s<<6 | fu->r<<5 | fu->type; + return mbuf_write_u8(mb, v); +} + + +int h264_fu_hdr_decode(struct h264_fu *fu, struct mbuf *mb) +{ + uint8_t v; + + if (mbuf_get_left(mb) < 1) + return ENOENT; + + v = mbuf_read_u8(mb); + + fu->s = v>>7 & 0x1; + fu->e = v>>6 & 0x1; + fu->r = v>>5 & 0x1; + fu->type = v>>0 & 0x1f; + + return 0; +} + + +/* + * Find the NAL start sequence in a H.264 byte stream + * + * @note: copied from ffmpeg source + */ +const uint8_t *h264_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*)(void *)p; + if ( (x - 0x01010101) & (~x) & 0x80808080 ) { + if (p[1] == 0 ) { + if ( p[0] == 0 && p[2] == 1 ) + return p; + if ( p[2] == 0 && p[3] == 1 ) + return p+1; + } + if ( p[3] == 0 ) { + if ( p[2] == 0 && p[4] == 1 ) + return p+2; + if ( p[4] == 0 && p[5] == 1 ) + return p+3; + } + } + } + + for (end += 3; p < end; p++) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + return end + 3; +} + + +static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz, + const uint8_t *buf, size_t sz, bool eof, + videnc_packet_h *pkth, void *arg) +{ + return pkth(eof, hdr, hdr_sz, buf, sz, arg); +} + + +int h264_nal_send(bool first, bool last, + bool marker, uint32_t ihdr, const uint8_t *buf, + size_t size, size_t maxsz, + videnc_packet_h *pkth, void *arg) +{ + uint8_t hdr = (uint8_t)ihdr; + int err = 0; + + if (first && last && size <= maxsz) { + err = rtp_send_data(&hdr, 1, buf, size, marker, + pkth, arg); + } + else { + uint8_t fu_hdr[2]; + const uint8_t type = hdr & 0x1f; + const uint8_t nri = hdr & 0x60; + const size_t sz = maxsz - 2; + + fu_hdr[0] = nri | H264_NAL_FU_A; + fu_hdr[1] = first ? (1<<7 | type) : type; + + while (size > sz) { + err |= rtp_send_data(fu_hdr, 2, buf, sz, false, + pkth, arg); + buf += sz; + size -= sz; + fu_hdr[1] &= ~(1 << 7); + } + + if (last) + fu_hdr[1] |= 1<<6; /* end bit */ + + err |= rtp_send_data(fu_hdr, 2, buf, size, marker && last, + pkth, arg); + } + + return err; +} + + +int h264_packetize(const uint8_t *buf, size_t len, size_t pktsize, + videnc_packet_h *pkth, void *arg) +{ + const uint8_t *start = buf; + const uint8_t *end = buf + len; + const uint8_t *r; + int err = 0; + + r = h264_find_startcode(start, end); + + while (r < end) { + const uint8_t *r1; + + /* skip zeros */ + while (!*(r++)) + ; + + r1 = h264_find_startcode(r, end); + + err |= h264_nal_send(true, true, (r1 >= end), r[0], + r+1, r1-r-1, pktsize, + pkth, arg); + r = r1; + } + + return err; +} diff --git a/src/srcs.mk b/src/srcs.mk index d3aa765..3c042ec 100644 --- a/src/srcs.mk +++ b/src/srcs.mk @@ -34,6 +34,7 @@ SRCS += ui.c ifneq ($(USE_VIDEO),) SRCS += bfcp.c +SRCS += h264.c SRCS += mctrl.c SRCS += video.c SRCS += vidcodec.c |