1 /**
2  * @file src/h264.c  H.264 video codec packetization (RFC 3984)
3  *
4  * Copyright (C) 2010 - 2015 Creytiv.com
5  */
6 #include <string.h>
7 #include <re.h>
8 #include <rem.h>
9 #include <baresip.h>
10 
11 
h264_hdr_encode(const struct h264_hdr * hdr,struct mbuf * mb)12 int h264_hdr_encode(const struct h264_hdr *hdr, struct mbuf *mb)
13 {
14 	uint8_t v;
15 
16 	v = hdr->f<<7 | hdr->nri<<5 | hdr->type<<0;
17 
18 	return mbuf_write_u8(mb, v);
19 }
20 
21 
h264_hdr_decode(struct h264_hdr * hdr,struct mbuf * mb)22 int h264_hdr_decode(struct h264_hdr *hdr, struct mbuf *mb)
23 {
24 	uint8_t v;
25 
26 	if (mbuf_get_left(mb) < 1)
27 		return ENOENT;
28 
29 	v = mbuf_read_u8(mb);
30 
31 	hdr->f    = v>>7 & 0x1;
32 	hdr->nri  = v>>5 & 0x3;
33 	hdr->type = v>>0 & 0x1f;
34 
35 	return 0;
36 }
37 
38 
h264_fu_hdr_encode(const struct h264_fu * fu,struct mbuf * mb)39 int h264_fu_hdr_encode(const struct h264_fu *fu, struct mbuf *mb)
40 {
41 	uint8_t v = fu->s<<7 | fu->s<<6 | fu->r<<5 | fu->type;
42 	return mbuf_write_u8(mb, v);
43 }
44 
45 
h264_fu_hdr_decode(struct h264_fu * fu,struct mbuf * mb)46 int h264_fu_hdr_decode(struct h264_fu *fu, struct mbuf *mb)
47 {
48 	uint8_t v;
49 
50 	if (mbuf_get_left(mb) < 1)
51 		return ENOENT;
52 
53 	v = mbuf_read_u8(mb);
54 
55 	fu->s    = v>>7 & 0x1;
56 	fu->e    = v>>6 & 0x1;
57 	fu->r    = v>>5 & 0x1;
58 	fu->type = v>>0 & 0x1f;
59 
60 	return 0;
61 }
62 
63 
64 /*
65  * Find the NAL start sequence in a H.264 byte stream
66  *
67  * @note: copied from ffmpeg source
68  */
h264_find_startcode(const uint8_t * p,const uint8_t * end)69 const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end)
70 {
71 	const uint8_t *a = p + 4 - ((long)p & 3);
72 
73 	for (end -= 3; p < a && p < end; p++ ) {
74 		if (p[0] == 0 && p[1] == 0 && p[2] == 1)
75 			return p;
76 	}
77 
78 	for (end -= 3; p < end; p += 4) {
79 		uint32_t x = *(const uint32_t*)(void *)p;
80 		if ( (x - 0x01010101) & (~x) & 0x80808080 ) {
81 			if (p[1] == 0 ) {
82 				if ( p[0] == 0 && p[2] == 1 )
83 					return p;
84 				if ( p[2] == 0 && p[3] == 1 )
85 					return p+1;
86 			}
87 			if ( p[3] == 0 ) {
88 				if ( p[2] == 0 && p[4] == 1 )
89 					return p+2;
90 				if ( p[4] == 0 && p[5] == 1 )
91 					return p+3;
92 			}
93 		}
94 	}
95 
96 	for (end += 3; p < end; p++) {
97 		if (p[0] == 0 && p[1] == 0 && p[2] == 1)
98 			return p;
99 	}
100 
101 	return end + 3;
102 }
103 
104 
rtp_send_data(const uint8_t * hdr,size_t hdr_sz,const uint8_t * buf,size_t sz,bool eof,uint32_t rtp_ts,videnc_packet_h * pkth,void * arg)105 static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz,
106 			 const uint8_t *buf, size_t sz,
107 			 bool eof, uint32_t rtp_ts,
108 			 videnc_packet_h *pkth, void *arg)
109 {
110 	return pkth(eof, rtp_ts, hdr, hdr_sz, buf, sz, arg);
111 }
112 
113 
h264_nal_send(bool first,bool last,bool marker,uint32_t ihdr,uint32_t rtp_ts,const uint8_t * buf,size_t size,size_t maxsz,videnc_packet_h * pkth,void * arg)114 int h264_nal_send(bool first, bool last,
115 		  bool marker, uint32_t ihdr, uint32_t rtp_ts,
116 		  const uint8_t *buf, size_t size, size_t maxsz,
117 		  videnc_packet_h *pkth, void *arg)
118 {
119 	uint8_t hdr = (uint8_t)ihdr;
120 	int err = 0;
121 
122 	if (first && last && size <= maxsz) {
123 		err = rtp_send_data(&hdr, 1, buf, size, marker, rtp_ts,
124 				    pkth, arg);
125 	}
126 	else {
127 		uint8_t fu_hdr[2];
128 		const uint8_t type = hdr & 0x1f;
129 		const uint8_t nri  = hdr & 0x60;
130 		const size_t sz = maxsz - 2;
131 
132 		fu_hdr[0] = nri | H264_NAL_FU_A;
133 		fu_hdr[1] = first ? (1<<7 | type) : type;
134 
135 		while (size > sz) {
136 			err |= rtp_send_data(fu_hdr, 2, buf, sz, false,
137 					     rtp_ts,
138 					     pkth, arg);
139 			buf += sz;
140 			size -= sz;
141 			fu_hdr[1] &= ~(1 << 7);
142 		}
143 
144 		if (last)
145 			fu_hdr[1] |= 1<<6;  /* end bit */
146 
147 		err |= rtp_send_data(fu_hdr, 2, buf, size, marker && last,
148 				     rtp_ts,
149 				     pkth, arg);
150 	}
151 
152 	return err;
153 }
154 
155 
h264_packetize(uint32_t rtp_ts,const uint8_t * buf,size_t len,size_t pktsize,videnc_packet_h * pkth,void * arg)156 int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
157 		   size_t pktsize, videnc_packet_h *pkth, void *arg)
158 {
159 	const uint8_t *start = buf;
160 	const uint8_t *end   = buf + len;
161 	const uint8_t *r;
162 	int err = 0;
163 
164 	r = h264_find_startcode(start, end);
165 
166 	while (r < end) {
167 		const uint8_t *r1;
168 
169 		/* skip zeros */
170 		while (!*(r++))
171 			;
172 
173 		r1 = h264_find_startcode(r, end);
174 
175 		err |= h264_nal_send(true, true, (r1 >= end), r[0],
176 				     rtp_ts, r+1, r1-r-1, pktsize,
177 				     pkth, arg);
178 		r = r1;
179 	}
180 
181 	return err;
182 }
183