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