• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
3  * Copyright © 2013 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 #include "config.h"
28 
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #include <errno.h>
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 
40 #include <pthread.h>
41 
42 #include <va/va.h>
43 #include <va/va_drm.h>
44 #include <va/va_drmcommon.h>
45 #include <va/va_enc_h264.h>
46 #include <va/va_vpp.h>
47 
48 #include <libweston/libweston.h>
49 #include "vaapi-recorder.h"
50 
51 #define NAL_REF_IDC_NONE        0
52 #define NAL_REF_IDC_LOW         1
53 #define NAL_REF_IDC_MEDIUM      2
54 #define NAL_REF_IDC_HIGH        3
55 
56 #define NAL_NON_IDR             1
57 #define NAL_IDR                 5
58 #define NAL_SPS                 7
59 #define NAL_PPS                 8
60 #define NAL_SEI                 6
61 
62 #define SLICE_TYPE_P            0
63 #define SLICE_TYPE_B            1
64 #define SLICE_TYPE_I            2
65 
66 #define ENTROPY_MODE_CAVLC      0
67 #define ENTROPY_MODE_CABAC      1
68 
69 #define PROFILE_IDC_BASELINE    66
70 #define PROFILE_IDC_MAIN        77
71 #define PROFILE_IDC_HIGH        100
72 
73 struct vaapi_recorder {
74 	int drm_fd, output_fd;
75 	int width, height;
76 	int frame_count;
77 
78 	int error;
79 	int destroying;
80 	pthread_t worker_thread;
81 	pthread_mutex_t mutex;
82 	pthread_cond_t input_cond;
83 
84 	struct {
85 		int valid;
86 		int prime_fd, stride;
87 	} input;
88 
89 	VADisplay va_dpy;
90 
91 	/* video post processing is used for colorspace conversion */
92 	struct {
93 		VAConfigID cfg;
94 		VAContextID ctx;
95 		VABufferID pipeline_buf;
96 		VASurfaceID output;
97 	} vpp;
98 
99 	struct {
100 		VAConfigID cfg;
101 		VAContextID ctx;
102 		VASurfaceID reference_picture[3];
103 
104 		int intra_period;
105 		int output_size;
106 		int constraint_set_flag;
107 
108 		struct {
109 			VAEncSequenceParameterBufferH264 seq;
110 			VAEncPictureParameterBufferH264 pic;
111 			VAEncSliceParameterBufferH264 slice;
112 		} param;
113 	} encoder;
114 };
115 
116 static void *
117 worker_thread_function(void *);
118 
119 /* bitstream code used for writing the packed headers */
120 
121 #define BITSTREAM_ALLOCATE_STEPPING	 4096
122 
123 struct bitstream {
124 	unsigned int *buffer;
125 	int bit_offset;
126 	int max_size_in_dword;
127 };
128 
129 static unsigned int
va_swap32(unsigned int val)130 va_swap32(unsigned int val)
131 {
132 	unsigned char *pval = (unsigned char *)&val;
133 
134 	return ((pval[0] << 24) |
135 		(pval[1] << 16) |
136 		(pval[2] << 8)  |
137 		(pval[3] << 0));
138 }
139 
140 static void
bitstream_start(struct bitstream * bs)141 bitstream_start(struct bitstream *bs)
142 {
143 	bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
144 	bs->buffer = calloc(bs->max_size_in_dword * sizeof(unsigned int), 1);
145 	bs->bit_offset = 0;
146 }
147 
148 static void
bitstream_end(struct bitstream * bs)149 bitstream_end(struct bitstream *bs)
150 {
151 	int pos = (bs->bit_offset >> 5);
152 	int bit_offset = (bs->bit_offset & 0x1f);
153 	int bit_left = 32 - bit_offset;
154 
155 	if (bit_offset) {
156 		bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
157 	}
158 }
159 
160 static void
bitstream_put_ui(struct bitstream * bs,unsigned int val,int size_in_bits)161 bitstream_put_ui(struct bitstream *bs, unsigned int val, int size_in_bits)
162 {
163 	int pos = (bs->bit_offset >> 5);
164 	int bit_offset = (bs->bit_offset & 0x1f);
165 	int bit_left = 32 - bit_offset;
166 
167 	if (!size_in_bits)
168 		return;
169 
170 	bs->bit_offset += size_in_bits;
171 
172 	if (bit_left > size_in_bits) {
173 		bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
174 		return;
175 	}
176 
177 	size_in_bits -= bit_left;
178 	bs->buffer[pos] =
179 		(bs->buffer[pos] << bit_left) | (val >> size_in_bits);
180 	bs->buffer[pos] = va_swap32(bs->buffer[pos]);
181 
182 	if (pos + 1 == bs->max_size_in_dword) {
183 		bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
184 		bs->buffer =
185 			realloc(bs->buffer,
186 				bs->max_size_in_dword * sizeof(unsigned int));
187 	}
188 
189 	bs->buffer[pos + 1] = val;
190 }
191 
192 static void
bitstream_put_ue(struct bitstream * bs,unsigned int val)193 bitstream_put_ue(struct bitstream *bs, unsigned int val)
194 {
195 	int size_in_bits = 0;
196 	int tmp_val = ++val;
197 
198 	while (tmp_val) {
199 		tmp_val >>= 1;
200 		size_in_bits++;
201 	}
202 
203 	bitstream_put_ui(bs, 0, size_in_bits - 1); /* leading zero */
204 	bitstream_put_ui(bs, val, size_in_bits);
205 }
206 
207 static void
bitstream_put_se(struct bitstream * bs,int val)208 bitstream_put_se(struct bitstream *bs, int val)
209 {
210 	unsigned int new_val;
211 
212 	if (val <= 0)
213 		new_val = -2 * val;
214 	else
215 		new_val = 2 * val - 1;
216 
217 	bitstream_put_ue(bs, new_val);
218 }
219 
220 static void
bitstream_byte_aligning(struct bitstream * bs,int bit)221 bitstream_byte_aligning(struct bitstream *bs, int bit)
222 {
223 	int bit_offset = (bs->bit_offset & 0x7);
224 	int bit_left = 8 - bit_offset;
225 	int new_val;
226 
227 	if (!bit_offset)
228 		return;
229 
230 	if (bit)
231 		new_val = (1 << bit_left) - 1;
232 	else
233 		new_val = 0;
234 
235 	bitstream_put_ui(bs, new_val, bit_left);
236 }
237 
238 static VAStatus
encoder_create_config(struct vaapi_recorder * r)239 encoder_create_config(struct vaapi_recorder *r)
240 {
241 	VAConfigAttrib attrib[2];
242 	VAStatus status;
243 
244 	/* FIXME: should check if VAEntrypointEncSlice is supported */
245 
246 	/* FIXME: should check if specified attributes are supported */
247 
248 	attrib[0].type = VAConfigAttribRTFormat;
249 	attrib[0].value = VA_RT_FORMAT_YUV420;
250 
251 	attrib[1].type = VAConfigAttribRateControl;
252 	attrib[1].value = VA_RC_CQP;
253 
254 	status = vaCreateConfig(r->va_dpy, VAProfileH264Main,
255 				VAEntrypointEncSlice, attrib, 2,
256 				&r->encoder.cfg);
257 	if (status != VA_STATUS_SUCCESS)
258 		return status;
259 
260 	status = vaCreateContext(r->va_dpy, r->encoder.cfg,
261 				 r->width, r->height, VA_PROGRESSIVE, 0, 0,
262 				 &r->encoder.ctx);
263 	if (status != VA_STATUS_SUCCESS) {
264 		vaDestroyConfig(r->va_dpy, r->encoder.cfg);
265 		return status;
266 	}
267 
268 	return VA_STATUS_SUCCESS;
269 }
270 
271 static void
encoder_destroy_config(struct vaapi_recorder * r)272 encoder_destroy_config(struct vaapi_recorder *r)
273 {
274 	vaDestroyContext(r->va_dpy, r->encoder.ctx);
275 	vaDestroyConfig(r->va_dpy, r->encoder.cfg);
276 }
277 
278 static void
encoder_init_seq_parameters(struct vaapi_recorder * r)279 encoder_init_seq_parameters(struct vaapi_recorder *r)
280 {
281 	int width_in_mbs, height_in_mbs;
282 	int frame_cropping_flag = 0;
283 	int frame_crop_bottom_offset = 0;
284 
285 	width_in_mbs = (r->width + 15) / 16;
286 	height_in_mbs = (r->height + 15) / 16;
287 
288 	r->encoder.param.seq.level_idc = 41;
289 	r->encoder.param.seq.intra_period = r->encoder.intra_period;
290 	r->encoder.param.seq.max_num_ref_frames = 4;
291 	r->encoder.param.seq.picture_width_in_mbs = width_in_mbs;
292 	r->encoder.param.seq.picture_height_in_mbs = height_in_mbs;
293 	r->encoder.param.seq.seq_fields.bits.frame_mbs_only_flag = 1;
294 
295 	/* Tc = num_units_in_tick / time_scale */
296 	r->encoder.param.seq.time_scale = 1800;
297 	r->encoder.param.seq.num_units_in_tick = 15;
298 
299 	if (height_in_mbs * 16 - r->height > 0) {
300 		frame_cropping_flag = 1;
301 		frame_crop_bottom_offset = (height_in_mbs * 16 - r->height) / 2;
302 	}
303 
304 	r->encoder.param.seq.frame_cropping_flag = frame_cropping_flag;
305 	r->encoder.param.seq.frame_crop_bottom_offset = frame_crop_bottom_offset;
306 
307 	r->encoder.param.seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
308 }
309 
310 static VABufferID
encoder_update_seq_parameters(struct vaapi_recorder * r)311 encoder_update_seq_parameters(struct vaapi_recorder *r)
312 {
313 	VABufferID seq_buf;
314 	VAStatus status;
315 
316 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
317 				VAEncSequenceParameterBufferType,
318 				sizeof(r->encoder.param.seq),
319 				1, &r->encoder.param.seq,
320 				&seq_buf);
321 
322 	if (status == VA_STATUS_SUCCESS)
323 		return seq_buf;
324 	else
325 		return VA_INVALID_ID;
326 }
327 
328 static void
encoder_init_pic_parameters(struct vaapi_recorder * r)329 encoder_init_pic_parameters(struct vaapi_recorder *r)
330 {
331 	VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
332 
333 	pic->pic_init_qp = 0;
334 
335 	/* ENTROPY_MODE_CABAC */
336 	pic->pic_fields.bits.entropy_coding_mode_flag = 1;
337 
338 	pic->pic_fields.bits.deblocking_filter_control_present_flag = 1;
339 }
340 
341 static VABufferID
encoder_update_pic_parameters(struct vaapi_recorder * r,VABufferID output_buf)342 encoder_update_pic_parameters(struct vaapi_recorder *r,
343 			      VABufferID output_buf)
344 {
345 	VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
346 	VAStatus status;
347 	VABufferID pic_param_buf;
348 	VASurfaceID curr_pic, pic0;
349 
350 	curr_pic = r->encoder.reference_picture[r->frame_count % 2];
351 	pic0 = r->encoder.reference_picture[(r->frame_count + 1) % 2];
352 
353 	pic->CurrPic.picture_id = curr_pic;
354 	pic->CurrPic.TopFieldOrderCnt = r->frame_count * 2;
355 	pic->ReferenceFrames[0].picture_id = pic0;
356 	pic->ReferenceFrames[1].picture_id = r->encoder.reference_picture[2];
357 	pic->ReferenceFrames[2].picture_id = VA_INVALID_ID;
358 
359 	pic->coded_buf = output_buf;
360 	pic->frame_num = r->frame_count;
361 
362 	pic->pic_fields.bits.idr_pic_flag = (r->frame_count == 0);
363 	pic->pic_fields.bits.reference_pic_flag = 1;
364 
365 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
366 				VAEncPictureParameterBufferType,
367 				sizeof(VAEncPictureParameterBufferH264), 1,
368 				pic, &pic_param_buf);
369 
370 	if (status == VA_STATUS_SUCCESS)
371 		return pic_param_buf;
372 	else
373 		return VA_INVALID_ID;
374 }
375 
376 static VABufferID
encoder_update_slice_parameter(struct vaapi_recorder * r,int slice_type)377 encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type)
378 {
379 	VABufferID slice_param_buf;
380 	VAStatus status;
381 
382 	int width_in_mbs = (r->width + 15) / 16;
383 	int height_in_mbs = (r->height + 15) / 16;
384 
385 	memset(&r->encoder.param.slice, 0, sizeof r->encoder.param.slice);
386 
387 	r->encoder.param.slice.num_macroblocks = width_in_mbs * height_in_mbs;
388 	r->encoder.param.slice.slice_type = slice_type;
389 
390 	r->encoder.param.slice.slice_alpha_c0_offset_div2 = 2;
391 	r->encoder.param.slice.slice_beta_offset_div2 = 2;
392 
393 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
394 				VAEncSliceParameterBufferType,
395 				sizeof(r->encoder.param.slice), 1,
396 				&r->encoder.param.slice,
397 				&slice_param_buf);
398 
399 	if (status == VA_STATUS_SUCCESS)
400 		return slice_param_buf;
401 	else
402 		return VA_INVALID_ID;
403 }
404 
405 static VABufferID
encoder_update_misc_hdr_parameter(struct vaapi_recorder * r)406 encoder_update_misc_hdr_parameter(struct vaapi_recorder *r)
407 {
408 	VAEncMiscParameterBuffer *misc_param;
409 	VAEncMiscParameterHRD *hrd;
410 	VABufferID buffer;
411 	VAStatus status;
412 
413 	int total_size =
414 		sizeof(VAEncMiscParameterBuffer) +
415 		sizeof(VAEncMiscParameterRateControl);
416 
417 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
418 				VAEncMiscParameterBufferType, total_size,
419 				1, NULL, &buffer);
420 	if (status != VA_STATUS_SUCCESS)
421 		return VA_INVALID_ID;
422 
423 	status = vaMapBuffer(r->va_dpy, buffer, (void **) &misc_param);
424 	if (status != VA_STATUS_SUCCESS) {
425 		vaDestroyBuffer(r->va_dpy, buffer);
426 		return VA_INVALID_ID;
427 	}
428 
429 	misc_param->type = VAEncMiscParameterTypeHRD;
430 	hrd = (VAEncMiscParameterHRD *) misc_param->data;
431 
432 	hrd->initial_buffer_fullness = 0;
433 	hrd->buffer_size = 0;
434 
435 	vaUnmapBuffer(r->va_dpy, buffer);
436 
437 	return buffer;
438 }
439 
440 static int
setup_encoder(struct vaapi_recorder * r)441 setup_encoder(struct vaapi_recorder *r)
442 {
443 	VAStatus status;
444 
445 	status = encoder_create_config(r);
446 	if (status != VA_STATUS_SUCCESS) {
447 		return -1;
448 	}
449 
450 	status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
451 				  r->width, r->height,
452 				  r->encoder.reference_picture, 3,
453 				  NULL, 0);
454 	if (status != VA_STATUS_SUCCESS) {
455 		encoder_destroy_config(r);
456 		return -1;
457 	}
458 
459 	/* VAProfileH264Main */
460 	r->encoder.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
461 
462 	r->encoder.output_size = r->width * r->height;
463 
464 	r->encoder.intra_period = 30;
465 
466 	encoder_init_seq_parameters(r);
467 	encoder_init_pic_parameters(r);
468 
469 	return 0;
470 }
471 
472 static void
encoder_destroy(struct vaapi_recorder * r)473 encoder_destroy(struct vaapi_recorder *r)
474 {
475 	vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
476 
477 	encoder_destroy_config(r);
478 }
479 
480 static void
nal_start_code_prefix(struct bitstream * bs)481 nal_start_code_prefix(struct bitstream *bs)
482 {
483 	bitstream_put_ui(bs, 0x00000001, 32);
484 }
485 
486 static void
nal_header(struct bitstream * bs,int nal_ref_idc,int nal_unit_type)487 nal_header(struct bitstream *bs, int nal_ref_idc, int nal_unit_type)
488 {
489 	/* forbidden_zero_bit: 0 */
490 	bitstream_put_ui(bs, 0, 1);
491 
492 	bitstream_put_ui(bs, nal_ref_idc, 2);
493 	bitstream_put_ui(bs, nal_unit_type, 5);
494 }
495 
496 static void
rbsp_trailing_bits(struct bitstream * bs)497 rbsp_trailing_bits(struct bitstream *bs)
498 {
499 	bitstream_put_ui(bs, 1, 1);
500 	bitstream_byte_aligning(bs, 0);
501 }
502 
sps_rbsp(struct bitstream * bs,VAEncSequenceParameterBufferH264 * seq,int constraint_set_flag)503 static void sps_rbsp(struct bitstream *bs,
504 		     VAEncSequenceParameterBufferH264 *seq,
505 		     int constraint_set_flag)
506 {
507 	int i;
508 
509 	bitstream_put_ui(bs, PROFILE_IDC_MAIN, 8);
510 
511 	/* constraint_set[0-3] flag */
512 	for (i = 0; i < 4; i++) {
513 		int set = (constraint_set_flag & (1 << i)) ? 1 : 0;
514 		bitstream_put_ui(bs, set, 1);
515 	}
516 
517 	/* reserved_zero_4bits */
518 	bitstream_put_ui(bs, 0, 4);
519 	bitstream_put_ui(bs, seq->level_idc, 8);
520 	bitstream_put_ue(bs, seq->seq_parameter_set_id);
521 
522 	bitstream_put_ue(bs, seq->seq_fields.bits.log2_max_frame_num_minus4);
523 	bitstream_put_ue(bs, seq->seq_fields.bits.pic_order_cnt_type);
524 	bitstream_put_ue(bs,
525 			 seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
526 
527 	bitstream_put_ue(bs, seq->max_num_ref_frames);
528 
529 	/* gaps_in_frame_num_value_allowed_flag */
530 	bitstream_put_ui(bs, 0, 1);
531 
532 	/* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */
533 	bitstream_put_ue(bs, seq->picture_width_in_mbs - 1);
534 	bitstream_put_ue(bs, seq->picture_height_in_mbs - 1);
535 
536 	bitstream_put_ui(bs, seq->seq_fields.bits.frame_mbs_only_flag, 1);
537 	bitstream_put_ui(bs, seq->seq_fields.bits.direct_8x8_inference_flag, 1);
538 
539 	bitstream_put_ui(bs, seq->frame_cropping_flag, 1);
540 
541 	if (seq->frame_cropping_flag) {
542 		bitstream_put_ue(bs, seq->frame_crop_left_offset);
543 		bitstream_put_ue(bs, seq->frame_crop_right_offset);
544 		bitstream_put_ue(bs, seq->frame_crop_top_offset);
545 		bitstream_put_ue(bs, seq->frame_crop_bottom_offset);
546 	}
547 
548 	/* vui_parameters_present_flag */
549 	bitstream_put_ui(bs, 1, 1);
550 
551 	/* aspect_ratio_info_present_flag */
552 	bitstream_put_ui(bs, 0, 1);
553 	/* overscan_info_present_flag */
554 	bitstream_put_ui(bs, 0, 1);
555 
556 	/* video_signal_type_present_flag */
557 	bitstream_put_ui(bs, 0, 1);
558 	/* chroma_loc_info_present_flag */
559 	bitstream_put_ui(bs, 0, 1);
560 
561 	/* timing_info_present_flag */
562 	bitstream_put_ui(bs, 1, 1);
563 	bitstream_put_ui(bs, seq->num_units_in_tick, 32);
564 	bitstream_put_ui(bs, seq->time_scale, 32);
565 	/* fixed_frame_rate_flag */
566 	bitstream_put_ui(bs, 1, 1);
567 
568 	/* nal_hrd_parameters_present_flag */
569 	bitstream_put_ui(bs, 0, 1);
570 
571 	/* vcl_hrd_parameters_present_flag */
572 	bitstream_put_ui(bs, 0, 1);
573 
574 	/* low_delay_hrd_flag */
575 	bitstream_put_ui(bs, 0, 1);
576 
577 	/* pic_struct_present_flag */
578 	bitstream_put_ui(bs, 0, 1);
579 	/* bitstream_restriction_flag */
580 	bitstream_put_ui(bs, 0, 1);
581 
582 	rbsp_trailing_bits(bs);
583 }
584 
pps_rbsp(struct bitstream * bs,VAEncPictureParameterBufferH264 * pic)585 static void pps_rbsp(struct bitstream *bs,
586 		     VAEncPictureParameterBufferH264 *pic)
587 {
588 	/* pic_parameter_set_id, seq_parameter_set_id */
589 	bitstream_put_ue(bs, pic->pic_parameter_set_id);
590 	bitstream_put_ue(bs, pic->seq_parameter_set_id);
591 
592 	bitstream_put_ui(bs, pic->pic_fields.bits.entropy_coding_mode_flag, 1);
593 
594 	/* pic_order_present_flag: 0 */
595 	bitstream_put_ui(bs, 0, 1);
596 
597 	/* num_slice_groups_minus1 */
598 	bitstream_put_ue(bs, 0);
599 
600 	bitstream_put_ue(bs, pic->num_ref_idx_l0_active_minus1);
601 	bitstream_put_ue(bs, pic->num_ref_idx_l1_active_minus1);
602 
603 	bitstream_put_ui(bs, pic->pic_fields.bits.weighted_pred_flag, 1);
604 	bitstream_put_ui(bs, pic->pic_fields.bits.weighted_bipred_idc, 2);
605 
606 	/* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */
607 	bitstream_put_se(bs, pic->pic_init_qp - 26);
608 	bitstream_put_se(bs, 0);
609 	bitstream_put_se(bs, 0);
610 
611 	bitstream_put_ui(bs, pic->pic_fields.bits.deblocking_filter_control_present_flag, 1);
612 
613 	/* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */
614 	bitstream_put_ui(bs, 0, 1);
615 	bitstream_put_ui(bs, 0, 1);
616 
617 	bitstream_put_ui(bs, pic->pic_fields.bits.transform_8x8_mode_flag, 1);
618 
619 	/* pic_scaling_matrix_present_flag */
620 	bitstream_put_ui(bs, 0, 1);
621 	bitstream_put_se(bs, pic->second_chroma_qp_index_offset );
622 
623 	rbsp_trailing_bits(bs);
624 }
625 
626 static int
build_packed_pic_buffer(struct vaapi_recorder * r,void ** header_buffer)627 build_packed_pic_buffer(struct vaapi_recorder *r,
628 			void **header_buffer)
629 {
630 	struct bitstream bs;
631 
632 	bitstream_start(&bs);
633 	nal_start_code_prefix(&bs);
634 	nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
635 	pps_rbsp(&bs, &r->encoder.param.pic);
636 	bitstream_end(&bs);
637 
638 	*header_buffer = bs.buffer;
639 	return bs.bit_offset;
640 }
641 
642 static int
build_packed_seq_buffer(struct vaapi_recorder * r,void ** header_buffer)643 build_packed_seq_buffer(struct vaapi_recorder *r,
644 			void **header_buffer)
645 {
646 	struct bitstream bs;
647 
648 	bitstream_start(&bs);
649 	nal_start_code_prefix(&bs);
650 	nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
651 	sps_rbsp(&bs, &r->encoder.param.seq, r->encoder.constraint_set_flag);
652 	bitstream_end(&bs);
653 
654 	*header_buffer = bs.buffer;
655 	return bs.bit_offset;
656 }
657 
658 static int
create_packed_header_buffers(struct vaapi_recorder * r,VABufferID * buffers,VAEncPackedHeaderType type,void * data,int bit_length)659 create_packed_header_buffers(struct vaapi_recorder *r, VABufferID *buffers,
660 			     VAEncPackedHeaderType type,
661 			     void *data, int bit_length)
662 {
663 	VAEncPackedHeaderParameterBuffer packed_header;
664 	VAStatus status;
665 
666 	packed_header.type = type;
667 	packed_header.bit_length = bit_length;
668 	packed_header.has_emulation_bytes = 0;
669 
670 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
671 				VAEncPackedHeaderParameterBufferType,
672 				sizeof packed_header, 1, &packed_header,
673 				&buffers[0]);
674 	if (status != VA_STATUS_SUCCESS)
675 		return 0;
676 
677 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
678 				VAEncPackedHeaderDataBufferType,
679 				(bit_length + 7) / 8, 1, data, &buffers[1]);
680 	if (status != VA_STATUS_SUCCESS) {
681 		vaDestroyBuffer(r->va_dpy, buffers[0]);
682 		return 0;
683 	}
684 
685 	return 2;
686 }
687 
688 static int
encoder_prepare_headers(struct vaapi_recorder * r,VABufferID * buffers)689 encoder_prepare_headers(struct vaapi_recorder *r, VABufferID *buffers)
690 {
691 	VABufferID *p;
692 
693 	int bit_length;
694 	void *data;
695 
696 	p = buffers;
697 
698 	bit_length = build_packed_seq_buffer(r, &data);
699 	p += create_packed_header_buffers(r, p, VAEncPackedHeaderSequence,
700 					  data, bit_length);
701 	free(data);
702 
703 	bit_length = build_packed_pic_buffer(r, &data);
704 	p += create_packed_header_buffers(r, p, VAEncPackedHeaderPicture,
705 					  data, bit_length);
706 	free(data);
707 
708 	return p - buffers;
709 }
710 
711 static VAStatus
encoder_render_picture(struct vaapi_recorder * r,VASurfaceID input,VABufferID * buffers,int count)712 encoder_render_picture(struct vaapi_recorder *r, VASurfaceID input,
713 		       VABufferID *buffers, int count)
714 {
715 	VAStatus status;
716 
717 	status = vaBeginPicture(r->va_dpy, r->encoder.ctx, input);
718 	if (status != VA_STATUS_SUCCESS)
719 		return status;
720 
721 	status = vaRenderPicture(r->va_dpy, r->encoder.ctx, buffers, count);
722 	if (status != VA_STATUS_SUCCESS)
723 		return status;
724 
725 	status = vaEndPicture(r->va_dpy, r->encoder.ctx);
726 	if (status != VA_STATUS_SUCCESS)
727 		return status;
728 
729 	return vaSyncSurface(r->va_dpy, input);
730 }
731 
732 static VABufferID
encoder_create_output_buffer(struct vaapi_recorder * r)733 encoder_create_output_buffer(struct vaapi_recorder *r)
734 {
735 	VABufferID output_buf;
736 	VAStatus status;
737 
738 	status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
739 				VAEncCodedBufferType, r->encoder.output_size,
740 				1, NULL, &output_buf);
741 	if (status == VA_STATUS_SUCCESS)
742 		return output_buf;
743 	else
744 		return VA_INVALID_ID;
745 }
746 
747 enum output_write_status {
748 	OUTPUT_WRITE_SUCCESS,
749 	OUTPUT_WRITE_OVERFLOW,
750 	OUTPUT_WRITE_FATAL
751 };
752 
753 static enum output_write_status
encoder_write_output(struct vaapi_recorder * r,VABufferID output_buf)754 encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
755 {
756 	VACodedBufferSegment *segment;
757 	VAStatus status;
758 	int count;
759 
760 	status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
761 	if (status != VA_STATUS_SUCCESS)
762 		return OUTPUT_WRITE_FATAL;
763 
764 	if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
765 		r->encoder.output_size *= 2;
766 		vaUnmapBuffer(r->va_dpy, output_buf);
767 		return OUTPUT_WRITE_OVERFLOW;
768 	}
769 
770 	count = write(r->output_fd, segment->buf, segment->size);
771 
772 	vaUnmapBuffer(r->va_dpy, output_buf);
773 
774 	if (count < 0)
775 		return OUTPUT_WRITE_FATAL;
776 
777 	return OUTPUT_WRITE_SUCCESS;
778 }
779 
780 static void
encoder_encode(struct vaapi_recorder * r,VASurfaceID input)781 encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
782 {
783 	VABufferID output_buf = VA_INVALID_ID;
784 
785 	VABufferID buffers[8];
786 	int count = 0;
787 	int i, slice_type;
788 	enum output_write_status ret;
789 
790 	if ((r->frame_count % r->encoder.intra_period) == 0)
791 		slice_type = SLICE_TYPE_I;
792 	else
793 		slice_type = SLICE_TYPE_P;
794 
795 	buffers[count++] = encoder_update_seq_parameters(r);
796 	buffers[count++] = encoder_update_misc_hdr_parameter(r);
797 	buffers[count++] = encoder_update_slice_parameter(r, slice_type);
798 
799 	for (i = 0; i < count; i++)
800 		if (buffers[i] == VA_INVALID_ID)
801 			goto bail;
802 
803 	if (r->frame_count == 0)
804 		count += encoder_prepare_headers(r, buffers + count);
805 
806 	do {
807 		output_buf = encoder_create_output_buffer(r);
808 		if (output_buf == VA_INVALID_ID)
809 			goto bail;
810 
811 		buffers[count++] =
812 			encoder_update_pic_parameters(r, output_buf);
813 		if (buffers[count - 1] == VA_INVALID_ID)
814 			goto bail;
815 
816 		encoder_render_picture(r, input, buffers, count);
817 		ret = encoder_write_output(r, output_buf);
818 
819 		vaDestroyBuffer(r->va_dpy, output_buf);
820 		output_buf = VA_INVALID_ID;
821 
822 		vaDestroyBuffer(r->va_dpy, buffers[--count]);
823 	} while (ret == OUTPUT_WRITE_OVERFLOW);
824 
825 	if (ret == OUTPUT_WRITE_FATAL)
826 		r->error = errno;
827 
828 	for (i = 0; i < count; i++)
829 		vaDestroyBuffer(r->va_dpy, buffers[i]);
830 
831 	r->frame_count++;
832 	return;
833 
834 bail:
835 	for (i = 0; i < count; i++)
836 		vaDestroyBuffer(r->va_dpy, buffers[i]);
837 	if (output_buf != VA_INVALID_ID)
838 		vaDestroyBuffer(r->va_dpy, output_buf);
839 }
840 
841 
842 static int
setup_vpp(struct vaapi_recorder * r)843 setup_vpp(struct vaapi_recorder *r)
844 {
845 	VAStatus status;
846 
847 	status = vaCreateConfig(r->va_dpy, VAProfileNone,
848 				VAEntrypointVideoProc, NULL, 0,
849 				&r->vpp.cfg);
850 	if (status != VA_STATUS_SUCCESS) {
851 		weston_log("vaapi: failed to create VPP config\n");
852 		return -1;
853 	}
854 
855 	status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
856 				 0, NULL, 0, &r->vpp.ctx);
857 	if (status != VA_STATUS_SUCCESS) {
858 		weston_log("vaapi: failed to create VPP context\n");
859 		goto err_cfg;
860 	}
861 
862 	status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
863 				VAProcPipelineParameterBufferType,
864 				sizeof(VAProcPipelineParameterBuffer),
865 				1, NULL, &r->vpp.pipeline_buf);
866 	if (status != VA_STATUS_SUCCESS) {
867 		weston_log("vaapi: failed to create VPP pipeline buffer\n");
868 		goto err_ctx;
869 	}
870 
871 	status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
872 				  r->width, r->height, &r->vpp.output, 1,
873 				  NULL, 0);
874 	if (status != VA_STATUS_SUCCESS) {
875 		weston_log("vaapi: failed to create YUV surface\n");
876 		goto err_buf;
877 	}
878 
879 	return 0;
880 
881 err_buf:
882 	vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
883 err_ctx:
884 	vaDestroyConfig(r->va_dpy, r->vpp.ctx);
885 err_cfg:
886 	vaDestroyConfig(r->va_dpy, r->vpp.cfg);
887 
888 	return -1;
889 }
890 
891 static void
vpp_destroy(struct vaapi_recorder * r)892 vpp_destroy(struct vaapi_recorder *r)
893 {
894 	vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
895 	vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
896 	vaDestroyConfig(r->va_dpy, r->vpp.ctx);
897 	vaDestroyConfig(r->va_dpy, r->vpp.cfg);
898 }
899 
900 static int
setup_worker_thread(struct vaapi_recorder * r)901 setup_worker_thread(struct vaapi_recorder *r)
902 {
903 	pthread_mutex_init(&r->mutex, NULL);
904 	pthread_cond_init(&r->input_cond, NULL);
905 	pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
906 
907 	return 1;
908 }
909 
910 static void
destroy_worker_thread(struct vaapi_recorder * r)911 destroy_worker_thread(struct vaapi_recorder *r)
912 {
913 	pthread_mutex_lock(&r->mutex);
914 
915 	/* Make sure the worker thread finishes */
916 	r->destroying = 1;
917 	pthread_cond_signal(&r->input_cond);
918 
919 	pthread_mutex_unlock(&r->mutex);
920 
921 	pthread_join(r->worker_thread, NULL);
922 
923 	pthread_mutex_destroy(&r->mutex);
924 	pthread_cond_destroy(&r->input_cond);
925 }
926 
927 struct vaapi_recorder *
vaapi_recorder_create(int drm_fd,int width,int height,const char * filename)928 vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
929 {
930 	struct vaapi_recorder *r;
931 	VAStatus status;
932 	int major, minor;
933 	int flags;
934 
935 	r = zalloc(sizeof *r);
936 	if (r == NULL)
937 		return NULL;
938 
939 	r->width = width;
940 	r->height = height;
941 	r->drm_fd = drm_fd;
942 
943 	if (setup_worker_thread(r) < 0)
944 		goto err_free;
945 
946 	flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
947 	r->output_fd = open(filename, flags, 0644);
948 	if (r->output_fd < 0)
949 		goto err_thread;
950 
951 	r->va_dpy = vaGetDisplayDRM(drm_fd);
952 	if (!r->va_dpy) {
953 		weston_log("failed to create VA display\n");
954 		goto err_fd;
955 	}
956 
957 	status = vaInitialize(r->va_dpy, &major, &minor);
958 	if (status != VA_STATUS_SUCCESS) {
959 		weston_log("vaapi: failed to initialize display\n");
960 		goto err_fd;
961 	}
962 
963 	if (setup_vpp(r) < 0) {
964 		weston_log("vaapi: failed to initialize VPP pipeline\n");
965 		goto err_va_dpy;
966 	}
967 
968 	if (setup_encoder(r) < 0) {
969 		goto err_vpp;
970 	}
971 
972 	return r;
973 
974 err_vpp:
975 	vpp_destroy(r);
976 err_va_dpy:
977 	vaTerminate(r->va_dpy);
978 err_fd:
979 	close(r->output_fd);
980 err_thread:
981 	destroy_worker_thread(r);
982 err_free:
983 	free(r);
984 
985 	return NULL;
986 }
987 
988 void
vaapi_recorder_destroy(struct vaapi_recorder * r)989 vaapi_recorder_destroy(struct vaapi_recorder *r)
990 {
991 	destroy_worker_thread(r);
992 
993 	encoder_destroy(r);
994 	vpp_destroy(r);
995 
996 	vaTerminate(r->va_dpy);
997 
998 	close(r->output_fd);
999 	close(r->drm_fd);
1000 
1001 	free(r);
1002 }
1003 
1004 static VAStatus
create_surface_from_fd(struct vaapi_recorder * r,int prime_fd,int stride,VASurfaceID * surface)1005 create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
1006 		       int stride, VASurfaceID *surface)
1007 {
1008 	VASurfaceAttrib va_attribs[2];
1009 	VASurfaceAttribExternalBuffers va_attrib_extbuf;
1010 	VAStatus status;
1011 
1012 	unsigned long buffer_fd = prime_fd;
1013 
1014 	va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
1015 	va_attrib_extbuf.width = r->width;
1016 	va_attrib_extbuf.height = r->height;
1017 	va_attrib_extbuf.data_size = r->height * stride;
1018 	va_attrib_extbuf.num_planes = 1;
1019 	va_attrib_extbuf.pitches[0] = stride;
1020 	va_attrib_extbuf.offsets[0] = 0;
1021 	va_attrib_extbuf.buffers = &buffer_fd;
1022 	va_attrib_extbuf.num_buffers = 1;
1023 	va_attrib_extbuf.flags = 0;
1024 	va_attrib_extbuf.private_data = NULL;
1025 
1026 	va_attribs[0].type = VASurfaceAttribMemoryType;
1027 	va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
1028 	va_attribs[0].value.type = VAGenericValueTypeInteger;
1029 	va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1030 
1031 	va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
1032 	va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
1033 	va_attribs[1].value.type = VAGenericValueTypePointer;
1034 	va_attribs[1].value.value.p = &va_attrib_extbuf;
1035 
1036 	status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
1037 				  r->width, r->height, surface, 1,
1038 				  va_attribs, 2);
1039 
1040 	return status;
1041 }
1042 
1043 static VAStatus
convert_rgb_to_yuv(struct vaapi_recorder * r,VASurfaceID rgb_surface)1044 convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
1045 {
1046 	VAProcPipelineParameterBuffer *pipeline_param;
1047 	VAStatus status;
1048 
1049 	status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
1050 			     (void **) &pipeline_param);
1051 	if (status != VA_STATUS_SUCCESS)
1052 		return status;
1053 
1054 	memset(pipeline_param, 0, sizeof *pipeline_param);
1055 
1056 	pipeline_param->surface = rgb_surface;
1057 	pipeline_param->surface_color_standard  = VAProcColorStandardNone;
1058 
1059 	pipeline_param->output_background_color = 0xff000000;
1060 	pipeline_param->output_color_standard   = VAProcColorStandardNone;
1061 
1062 	status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
1063 	if (status != VA_STATUS_SUCCESS)
1064 		return status;
1065 
1066 	status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
1067 	if (status != VA_STATUS_SUCCESS)
1068 		return status;
1069 
1070 	status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
1071 				 &r->vpp.pipeline_buf, 1);
1072 	if (status != VA_STATUS_SUCCESS)
1073 		return status;
1074 
1075 	status = vaEndPicture(r->va_dpy, r->vpp.ctx);
1076 	if (status != VA_STATUS_SUCCESS)
1077 		return status;
1078 
1079 	return status;
1080 }
1081 
1082 static void
recorder_frame(struct vaapi_recorder * r)1083 recorder_frame(struct vaapi_recorder *r)
1084 {
1085 	VASurfaceID rgb_surface;
1086 	VAStatus status;
1087 
1088 	status = create_surface_from_fd(r, r->input.prime_fd,
1089 					r->input.stride, &rgb_surface);
1090 	if (status != VA_STATUS_SUCCESS) {
1091 		weston_log("[libva recorder] "
1092 			   "failed to create surface from bo\n");
1093 		return;
1094 	}
1095 
1096 	close(r->input.prime_fd);
1097 
1098 	status = convert_rgb_to_yuv(r, rgb_surface);
1099 	if (status != VA_STATUS_SUCCESS) {
1100 		weston_log("[libva recorder] "
1101 			   "color space conversion failed\n");
1102 		return;
1103 	}
1104 
1105 	encoder_encode(r, r->vpp.output);
1106 
1107 	vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
1108 }
1109 
1110 static void *
worker_thread_function(void * data)1111 worker_thread_function(void *data)
1112 {
1113 	struct vaapi_recorder *r = data;
1114 
1115 	pthread_mutex_lock(&r->mutex);
1116 
1117 	while (!r->destroying) {
1118 		if (!r->input.valid)
1119 			pthread_cond_wait(&r->input_cond, &r->mutex);
1120 
1121 		/* If the thread is awaken by destroy_worker_thread(),
1122 		 * there might not be valid input */
1123 		if (!r->input.valid)
1124 			continue;
1125 
1126 		recorder_frame(r);
1127 		r->input.valid = 0;
1128 	}
1129 
1130 	pthread_mutex_unlock(&r->mutex);
1131 
1132 	return NULL;
1133 }
1134 
1135 int
vaapi_recorder_frame(struct vaapi_recorder * r,int prime_fd,int stride)1136 vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
1137 {
1138 	int ret = 0;
1139 
1140 	pthread_mutex_lock(&r->mutex);
1141 
1142 	if (r->error) {
1143 		errno = r->error;
1144 		ret = -1;
1145 		goto unlock;
1146 	}
1147 
1148 	/* The mutex is never released while encoding, so this point should
1149 	 * never be reached if input.valid is true. */
1150 	assert(!r->input.valid);
1151 
1152 	r->input.prime_fd = prime_fd;
1153 	r->input.stride = stride;
1154 	r->input.valid = 1;
1155 	pthread_cond_signal(&r->input_cond);
1156 
1157 unlock:
1158 	pthread_mutex_unlock(&r->mutex);
1159 
1160 	return ret;
1161 }
1162