1
2
3
4
5
6
7
8#include <linux/log2.h>
9
10#include "tw5864.h"
11
12static u8 marker[] = { 0x00, 0x00, 0x00, 0x01 };
13
14
15
16
17
18
19
20
21
22
23
24struct bs {
25 u8 *buf;
26 u8 *buf_end;
27 u8 *ptr;
28 unsigned int bits_left;
29};
30
31static void bs_init(struct bs *s, void *buf, int size)
32{
33 s->buf = buf;
34 s->ptr = buf;
35 s->buf_end = s->ptr + size;
36 s->bits_left = 8;
37}
38
39static int bs_len(struct bs *s)
40{
41 return s->ptr - s->buf;
42}
43
44static void bs_write(struct bs *s, int count, u32 bits)
45{
46 if (s->ptr >= s->buf_end - 4)
47 return;
48 while (count > 0) {
49 if (count < 32)
50 bits &= (1 << count) - 1;
51 if (count < s->bits_left) {
52 *s->ptr = (*s->ptr << count) | bits;
53 s->bits_left -= count;
54 break;
55 }
56 *s->ptr = (*s->ptr << s->bits_left) |
57 (bits >> (count - s->bits_left));
58 count -= s->bits_left;
59 s->ptr++;
60 s->bits_left = 8;
61 }
62}
63
64static void bs_write1(struct bs *s, u32 bit)
65{
66 if (s->ptr < s->buf_end) {
67 *s->ptr <<= 1;
68 *s->ptr |= bit;
69 s->bits_left--;
70 if (s->bits_left == 0) {
71 s->ptr++;
72 s->bits_left = 8;
73 }
74 }
75}
76
77static void bs_write_ue(struct bs *s, u32 val)
78{
79 if (val == 0) {
80 bs_write1(s, 1);
81 } else {
82 val++;
83 bs_write(s, 2 * fls(val) - 1, val);
84 }
85}
86
87static void bs_write_se(struct bs *s, int val)
88{
89 bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1);
90}
91
92static void bs_rbsp_trailing(struct bs *s)
93{
94 bs_write1(s, 1);
95 if (s->bits_left != 8)
96 bs_write(s, s->bits_left, 0x00);
97}
98
99
100
101static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height)
102{
103 struct bs bs, *s;
104
105 s = &bs;
106 bs_init(s, buf, size);
107 bs_write(s, 8, 0x42);
108 bs_write(s, 1, 1);
109 bs_write(s, 1, 1);
110 bs_write(s, 1, 0);
111 bs_write(s, 5, 0);
112 bs_write(s, 8, 0x1e);
113 bs_write_ue(s, 0);
114 bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4);
115 bs_write_ue(s, 0);
116
117 bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4);
118 bs_write_ue(s, 1);
119 bs_write(s, 1, 0);
120 bs_write_ue(s, width / 16 - 1);
121 bs_write_ue(s, height / 16 - 1);
122 bs_write(s, 1, 1);
123 bs_write(s, 1, 0);
124 bs_write(s, 1, 0);
125 bs_write(s, 1, 0);
126 bs_rbsp_trailing(s);
127 return bs_len(s);
128}
129
130static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp)
131{
132 struct bs bs, *s;
133
134 s = &bs;
135 bs_init(s, buf, size);
136 bs_write_ue(s, 0);
137 bs_write_ue(s, 0);
138 bs_write(s, 1, 0);
139 bs_write(s, 1, 0);
140 bs_write_ue(s, 0);
141 bs_write_ue(s, 0);
142 bs_write_ue(s, 0);
143 bs_write(s, 1, 0);
144 bs_write(s, 2, 0);
145 bs_write_se(s, qp - 26);
146 bs_write_se(s, qp - 26);
147 bs_write_se(s, 0);
148 bs_write(s, 1, 0);
149 bs_write(s, 1, 0);
150 bs_write(s, 1, 0);
151 bs_rbsp_trailing(s);
152 return bs_len(s);
153}
154
155static int tw5864_h264_gen_slice_head(u8 *buf, size_t size,
156 unsigned int idr_pic_id,
157 unsigned int frame_gop_seqno,
158 int *tail_nb_bits, u8 *tail)
159{
160 struct bs bs, *s;
161 int is_i_frame = frame_gop_seqno == 0;
162
163 s = &bs;
164 bs_init(s, buf, size);
165 bs_write_ue(s, 0);
166 bs_write_ue(s, is_i_frame ? 2 : 5);
167 bs_write_ue(s, 0);
168 bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno);
169 if (is_i_frame)
170 bs_write_ue(s, idr_pic_id);
171
172
173 bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno);
174
175 if (is_i_frame) {
176 bs_write1(s, 0);
177 bs_write1(s, 0);
178 } else {
179 bs_write1(s, 0);
180 bs_write1(s, 0);
181 bs_write1(s, 0);
182 }
183
184 bs_write_se(s, 0);
185
186 if (s->bits_left != 8) {
187 *tail = ((s->ptr[0]) << s->bits_left);
188 *tail_nb_bits = 8 - s->bits_left;
189 } else {
190 *tail = 0;
191 *tail_nb_bits = 0;
192 }
193
194 return bs_len(s);
195}
196
197void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp,
198 int width, int height)
199{
200 int nal_len;
201
202
203 memcpy(*buf, marker, sizeof(marker));
204 *buf += 4;
205 *space_left -= 4;
206
207 **buf = 0x67;
208 *buf += 1;
209 *space_left -= 1;
210
211 nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height);
212 *buf += nal_len;
213 *space_left -= nal_len;
214
215
216 memcpy(*buf, marker, sizeof(marker));
217 *buf += 4;
218 *space_left -= 4;
219
220 **buf = 0x68;
221 *buf += 1;
222 *space_left -= 1;
223
224 nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp);
225 *buf += nal_len;
226 *space_left -= nal_len;
227}
228
229void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left,
230 unsigned int idr_pic_id,
231 unsigned int frame_gop_seqno,
232 int *tail_nb_bits, u8 *tail)
233{
234 int nal_len;
235
236 memcpy(*buf, marker, sizeof(marker));
237 *buf += 4;
238 *space_left -= 4;
239
240
241 **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21;
242 *buf += 1;
243 *space_left -= 1;
244
245 nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id,
246 frame_gop_seqno, tail_nb_bits,
247 tail);
248 *buf += nal_len;
249 *space_left -= nal_len;
250}
251