1 /**
2 * @file h265/decode.c H.265 Decode
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7 #include <re.h>
8 #include <rem.h>
9 #include <baresip.h>
10 #include <libavutil/pixdesc.h>
11 #include <libavcodec/avcodec.h>
12 #include "h265.h"
13
14
15 #if LIBAVUTIL_VERSION_MAJOR < 52
16 #define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
17 #endif
18
19
20 enum {
21 FU_HDR_SIZE = 1
22 };
23
24 enum {
25 DECODE_MAXSZ = 524288,
26 };
27
28
29 struct fu {
30 unsigned s:1;
31 unsigned e:1;
32 unsigned type:6;
33 };
34
35 struct viddec_state {
36 AVCodecContext *ctx;
37 AVFrame *pict;
38 struct mbuf *mb;
39 size_t frag_start;
40 bool frag;
41 uint16_t frag_seq;
42 };
43
44
destructor(void * arg)45 static void destructor(void *arg)
46 {
47 struct viddec_state *vds = arg;
48
49 if (vds->ctx) {
50 avcodec_close(vds->ctx);
51 av_free(vds->ctx);
52 }
53
54 if (vds->pict)
55 av_free(vds->pict);
56
57 mem_deref(vds->mb);
58 }
59
60
h265_decode_update(struct viddec_state ** vdsp,const struct vidcodec * vc,const char * fmtp)61 int h265_decode_update(struct viddec_state **vdsp, const struct vidcodec *vc,
62 const char *fmtp)
63 {
64 struct viddec_state *vds;
65 AVCodec *codec;
66 int err = 0;
67 (void)vc;
68 (void)fmtp;
69
70 if (!vdsp)
71 return EINVAL;
72
73 vds = *vdsp;
74
75 if (vds)
76 return 0;
77
78 /* HEVC = H.265 */
79 codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
80 if (!codec) {
81 warning("h265: could not find H265 decoder\n");
82 return ENOSYS;
83 }
84
85 vds = mem_zalloc(sizeof(*vds), destructor);
86 if (!vds)
87 return ENOMEM;
88
89 vds->mb = mbuf_alloc(1024);
90 if (!vds->mb) {
91 err = ENOMEM;
92 goto out;
93 }
94
95 vds->pict = av_frame_alloc();
96 if (!vds->pict) {
97 err = ENOMEM;
98 goto out;
99 }
100
101 vds->ctx = avcodec_alloc_context3(codec);
102 if (!vds->ctx) {
103 err = ENOMEM;
104 goto out;
105 }
106
107 if (avcodec_open2(vds->ctx, codec, NULL) < 0) {
108 err = ENOMEM;
109 goto out;
110 }
111
112 out:
113 if (err)
114 mem_deref(vds);
115 else
116 *vdsp = vds;
117
118 return err;
119 }
120
121
fu_decode(struct fu * fu,struct mbuf * mb)122 static inline int fu_decode(struct fu *fu, struct mbuf *mb)
123 {
124 uint8_t v;
125
126 if (mbuf_get_left(mb) < 1)
127 return EBADMSG;
128
129 v = mbuf_read_u8(mb);
130
131 fu->s = v>>7 & 0x1;
132 fu->e = v>>6 & 0x1;
133 fu->type = v>>0 & 0x3f;
134
135 return 0;
136 }
137
138
seq_diff(uint16_t x,uint16_t y)139 static inline int16_t seq_diff(uint16_t x, uint16_t y)
140 {
141 return (int16_t)(y - x);
142 }
143
144
fragment_rewind(struct viddec_state * vds)145 static inline void fragment_rewind(struct viddec_state *vds)
146 {
147 vds->mb->pos = vds->frag_start;
148 vds->mb->end = vds->frag_start;
149 }
150
151
h265_decode(struct viddec_state * vds,struct vidframe * frame,bool * intra,bool marker,uint16_t seq,struct mbuf * mb)152 int h265_decode(struct viddec_state *vds, struct vidframe *frame,
153 bool *intra, bool marker, uint16_t seq, struct mbuf *mb)
154 {
155 static const uint8_t nal_seq[3] = {0, 0, 1};
156 int err, ret, got_picture, i;
157 struct h265_nal hdr;
158 AVPacket avpkt;
159 enum vidfmt fmt;
160
161 if (!vds || !frame || !intra || !mb)
162 return EINVAL;
163
164 *intra = false;
165
166 err = h265_nal_decode(&hdr, mbuf_buf(mb));
167 if (err)
168 return err;
169
170 mbuf_advance(mb, H265_HDR_SIZE);
171
172 #if 0
173 debug("h265: decode: %s type=%2d %s\n",
174 h265_is_keyframe(hdr.nal_unit_type) ? "<KEY>" : " ",
175 hdr.nal_unit_type,
176 h265_nalunit_name(hdr.nal_unit_type));
177 #endif
178
179 if (vds->frag && hdr.nal_unit_type != H265_NAL_FU) {
180 debug("h265: lost fragments; discarding previous NAL\n");
181 fragment_rewind(vds);
182 vds->frag = false;
183 }
184
185 /* handle NAL types */
186 if (0 <= hdr.nal_unit_type && hdr.nal_unit_type <= 40) {
187
188 if (h265_is_keyframe(hdr.nal_unit_type))
189 *intra = true;
190
191 mb->pos -= H265_HDR_SIZE;
192
193 err = mbuf_write_mem(vds->mb, nal_seq, 3);
194 err |= mbuf_write_mem(vds->mb, mbuf_buf(mb),mbuf_get_left(mb));
195 if (err)
196 goto out;
197 }
198 else if (H265_NAL_FU == hdr.nal_unit_type) {
199
200 struct fu fu;
201
202 err = fu_decode(&fu, mb);
203 if (err)
204 return err;
205
206 if (fu.s) {
207 if (h265_is_keyframe(fu.type))
208 *intra = true;
209
210 if (vds->frag) {
211 debug("h265: lost fragments; ignoring NAL\n");
212 fragment_rewind(vds);
213 }
214
215 vds->frag_start = vds->mb->pos;
216 vds->frag = true;
217
218 hdr.nal_unit_type = fu.type;
219
220 err = mbuf_write_mem(vds->mb, nal_seq, 3);
221 err = h265_nal_encode_mbuf(vds->mb, &hdr);
222 if (err)
223 goto out;
224 }
225 else {
226 if (!vds->frag) {
227 debug("h265: ignoring fragment\n");
228 return 0;
229 }
230
231 if (seq_diff(vds->frag_seq, seq) != 1) {
232 debug("h265: lost fragments detected\n");
233 fragment_rewind(vds);
234 vds->frag = false;
235 return 0;
236 }
237 }
238
239 err = mbuf_write_mem(vds->mb, mbuf_buf(mb), mbuf_get_left(mb));
240 if (err)
241 goto out;
242
243 if (fu.e)
244 vds->frag = false;
245
246 vds->frag_seq = seq;
247 }
248 else {
249 warning("h265: unknown NAL type %u (%s) [%zu bytes]\n",
250 hdr.nal_unit_type,
251 h265_nalunit_name(hdr.nal_unit_type),
252 mbuf_get_left(mb));
253 return EPROTO;
254 }
255
256 if (!marker) {
257
258 if (vds->mb->end > DECODE_MAXSZ) {
259 warning("h265: decode buffer size exceeded\n");
260 err = ENOMEM;
261 goto out;
262 }
263
264 return 0;
265 }
266
267 if (vds->frag) {
268 err = EPROTO;
269 goto out;
270 }
271
272 av_init_packet(&avpkt);
273 avpkt.data = vds->mb->buf;
274 avpkt.size = (int)vds->mb->end;
275
276 #if LIBAVCODEC_VERSION_INT >= ((57<<16)+(37<<8)+100)
277
278 ret = avcodec_send_packet(vds->ctx, &avpkt);
279 if (ret < 0) {
280 err = EBADMSG;
281 goto out;
282 }
283
284 ret = avcodec_receive_frame(vds->ctx, vds->pict);
285 if (ret < 0) {
286 err = EBADMSG;
287 goto out;
288 }
289
290 got_picture = true;
291
292 #else
293 ret = avcodec_decode_video2(vds->ctx, vds->pict, &got_picture, &avpkt);
294 if (ret < 0) {
295 debug("h265: decode error\n");
296 err = EPROTO;
297 goto out;
298 }
299 #endif
300
301 if (!got_picture) {
302 /* debug("h265: no picture\n"); */
303 goto out;
304 }
305
306 switch (vds->pict->format) {
307
308 case AV_PIX_FMT_YUV420P:
309 fmt = VID_FMT_YUV420P;
310 break;
311
312 case AV_PIX_FMT_YUV444P:
313 fmt = VID_FMT_YUV444P;
314 break;
315
316 default:
317 warning("h265: decode: bad pixel format (%i) (%s)\n",
318 vds->pict->format,
319 av_get_pix_fmt_name(vds->pict->format));
320 goto out;
321 }
322
323 for (i=0; i<4; i++) {
324 frame->data[i] = vds->pict->data[i];
325 frame->linesize[i] = vds->pict->linesize[i];
326 }
327
328 frame->size.w = vds->ctx->width;
329 frame->size.h = vds->ctx->height;
330 frame->fmt = fmt;
331
332 out:
333 mbuf_rewind(vds->mb);
334 vds->frag = false;
335
336 return err;
337 }
338