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