blob: c0210f0358d2d1721064c05904e320973b1b9fbc [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
46#include <stdlib.h>
47#include <stdint.h>
48#include <string.h>
49#include <unistd.h>
50
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <fcntl.h>
54
55
56#include <va/va.h>
57#include <va/va_drm.h>
58#include <va/va_drmcommon.h>
59#include <va/va_enc_h264.h>
60#include <va/va_vpp.h>
61
62#include "compositor.h"
63#include "vaapi-recorder.h"
64
65#define NAL_REF_IDC_NONE 0
66#define NAL_REF_IDC_LOW 1
67#define NAL_REF_IDC_MEDIUM 2
68#define NAL_REF_IDC_HIGH 3
69
70#define NAL_NON_IDR 1
71#define NAL_IDR 5
72#define NAL_SPS 7
73#define NAL_PPS 8
74#define NAL_SEI 6
75
76#define SLICE_TYPE_P 0
77#define SLICE_TYPE_B 1
78#define SLICE_TYPE_I 2
79
80#define ENTROPY_MODE_CAVLC 0
81#define ENTROPY_MODE_CABAC 1
82
83#define PROFILE_IDC_BASELINE 66
84#define PROFILE_IDC_MAIN 77
85#define PROFILE_IDC_HIGH 100
86
87struct vaapi_recorder {
88 int output_fd;
89 int width, height;
90 int frame_count;
91
92 VADisplay va_dpy;
93
94 /* video post processing is used for colorspace conversion */
95 struct {
96 VAConfigID cfg;
97 VAContextID ctx;
98 VABufferID pipeline_buf;
99 VASurfaceID output;
100 } vpp;
101
102 struct {
103 VAConfigID cfg;
104 VAContextID ctx;
105 VASurfaceID reference_picture[3];
106
107 int intra_period;
108 int output_size;
109 int constraint_set_flag;
110
111 struct {
112 VAEncSequenceParameterBufferH264 seq;
113 VAEncPictureParameterBufferH264 pic;
114 VAEncSliceParameterBufferH264 slice;
115 } param;
116 } encoder;
117};
118
119/* bistream code used for writing the packed headers */
120
121#define BITSTREAM_ALLOCATE_STEPPING 4096
122
123struct bitstream {
124 unsigned int *buffer;
125 int bit_offset;
126 int max_size_in_dword;
127};
128
129static unsigned int
130va_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
140static void
141bitstream_start(struct bitstream *bs)
142{
143 bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
144 bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
145 bs->bit_offset = 0;
146}
147
148static void
149bitstream_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
160static void
161bitstream_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
192static void
193bitstream_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
207static void
208bitstream_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
220static void
221bitstream_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
238static VAStatus
239encoder_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
271static void
272encoder_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
278static void
279encoder_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
310static VABufferID
311encoder_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
328static void
329encoder_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
341static VABufferID
342encoder_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
376static VABufferID
377encoder_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
405static VABufferID
406encoder_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
440static int
441setup_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
472static void
473encoder_destroy(struct vaapi_recorder *r)
474{
475 vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
476
477 encoder_destroy_config(r);
478}
479
480static void
481nal_start_code_prefix(struct bitstream *bs)
482{
483 bitstream_put_ui(bs, 0x00000001, 32);
484}
485
486static void
487nal_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
496static void
497rbsp_trailing_bits(struct bitstream *bs)
498{
499 bitstream_put_ui(bs, 1, 1);
500 bitstream_byte_aligning(bs, 0);
501}
502
503static 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
585static 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
626static int
627build_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
642static int
643build_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
658static int
659create_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
688static int
689encoder_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
711static VAStatus
712encoder_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
732static VABufferID
733encoder_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
747static int
748encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
749{
750 VACodedBufferSegment *segment;
751 VAStatus status;
752 int count;
753
754 status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
755 if (status != VA_STATUS_SUCCESS)
756 return -1;
757
758 if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
759 r->encoder.output_size *= 2;
760 vaUnmapBuffer(r->va_dpy, output_buf);
761 return -1;
762 }
763
764 count = write(r->output_fd, segment->buf, segment->size);
765
766 vaUnmapBuffer(r->va_dpy, output_buf);
767
768 return count;
769}
770
771static void
772encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
773{
774 VABufferID output_buf = VA_INVALID_ID;
775
776 VABufferID buffers[8];
777 int count = 0;
778
779 int slice_type;
780 int ret, i;
781
782 if ((r->frame_count % r->encoder.intra_period) == 0)
783 slice_type = SLICE_TYPE_I;
784 else
785 slice_type = SLICE_TYPE_P;
786
787 buffers[count++] = encoder_update_seq_parameters(r);
788 buffers[count++] = encoder_update_misc_hdr_parameter(r);
789 buffers[count++] = encoder_update_slice_parameter(r, slice_type);
790
791 for (i = 0; i < count; i++)
792 if (buffers[i] == VA_INVALID_ID)
793 goto bail;
794
795 if (r->frame_count == 0)
796 count += encoder_prepare_headers(r, buffers + count);
797
798 do {
799 output_buf = encoder_create_output_buffer(r);
800 if (output_buf == VA_INVALID_ID)
801 goto bail;
802
803 buffers[count++] =
804 encoder_update_pic_parameters(r, output_buf);
805 if (buffers[count - 1] == VA_INVALID_ID)
806 goto bail;
807
808 encoder_render_picture(r, input, buffers, count);
809 ret = encoder_write_output(r, output_buf);
810
811 vaDestroyBuffer(r->va_dpy, output_buf);
812 output_buf = VA_INVALID_ID;
813
814 vaDestroyBuffer(r->va_dpy, buffers[--count]);
815 } while (ret < 0);
816
817 for (i = 0; i < count; i++)
818 vaDestroyBuffer(r->va_dpy, buffers[i]);
819
820 r->frame_count++;
821 return;
822
823bail:
824 for (i = 0; i < count; i++)
825 vaDestroyBuffer(r->va_dpy, buffers[i]);
826 if (output_buf != VA_INVALID_ID)
827 vaDestroyBuffer(r->va_dpy, output_buf);
828}
829
830
831static int
832setup_vpp(struct vaapi_recorder *r)
833{
834 VAStatus status;
835
836 status = vaCreateConfig(r->va_dpy, VAProfileNone,
837 VAEntrypointVideoProc, NULL, 0,
838 &r->vpp.cfg);
839 if (status != VA_STATUS_SUCCESS) {
840 weston_log("vaapi: failed to create VPP config\n");
841 return -1;
842 }
843
844 status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
845 0, NULL, 0, &r->vpp.ctx);
846 if (status != VA_STATUS_SUCCESS) {
847 weston_log("vaapi: failed to create VPP context\n");
848 goto err_cfg;
849 }
850
851 status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
852 VAProcPipelineParameterBufferType,
853 sizeof(VAProcPipelineParameterBuffer),
854 1, NULL, &r->vpp.pipeline_buf);
855 if (status != VA_STATUS_SUCCESS) {
856 weston_log("vaapi: failed to create VPP pipeline buffer\n");
857 goto err_ctx;
858 }
859
860 status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
861 r->width, r->height, &r->vpp.output, 1,
862 NULL, 0);
863 if (status != VA_STATUS_SUCCESS) {
864 weston_log("vaapi: failed to create YUV surface\n");
865 goto err_buf;
866 }
867
868 return 0;
869
870err_buf:
871 vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
872err_ctx:
873 vaDestroyConfig(r->va_dpy, r->vpp.ctx);
874err_cfg:
875 vaDestroyConfig(r->va_dpy, r->vpp.cfg);
876
877 return -1;
878}
879
880static void
881vpp_destroy(struct vaapi_recorder *r)
882{
883 vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
884 vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
885 vaDestroyConfig(r->va_dpy, r->vpp.ctx);
886 vaDestroyConfig(r->va_dpy, r->vpp.cfg);
887}
888
889struct vaapi_recorder *
890vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
891{
892 struct vaapi_recorder *r;
893 VAStatus status;
894 int major, minor;
895 int flags;
896
897 r = calloc(1, sizeof *r);
898 if (!r)
899 return NULL;
900
901 r->width = width;
902 r->height = height;
903
904 flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
905 r->output_fd = open(filename, flags, 0644);
906
907 if (r->output_fd < 0)
908 goto err_free;
909
910 r->va_dpy = vaGetDisplayDRM(drm_fd);
911 if (!r->va_dpy) {
912 weston_log("failed to create VA display\n");
913 goto err_fd;
914 }
915
916 status = vaInitialize(r->va_dpy, &major, &minor);
917 if (status != VA_STATUS_SUCCESS) {
918 weston_log("vaapi: failed to initialize display\n");
919 goto err_fd;
920 }
921
922 if (setup_vpp(r) < 0) {
923 weston_log("vaapi: failed to initialize VPP pipeline\n");
924 goto err_va_dpy;
925 }
926
927 if (setup_encoder(r) < 0) {
928 goto err_vpp;
929 }
930
931 return r;
932
933err_vpp:
934 vpp_destroy(r);
935err_va_dpy:
936 vaTerminate(r->va_dpy);
937err_fd:
938 close(r->output_fd);
939err_free:
940 free(r);
941
942 return NULL;
943}
944
945void
946vaapi_recorder_destroy(struct vaapi_recorder *r)
947{
948 encoder_destroy(r);
949 vpp_destroy(r);
950
951 vaTerminate(r->va_dpy);
952
953 close(r->output_fd);
954
955 free(r);
956}
957
958static VAStatus
959create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
960 int stride, VASurfaceID *surface)
961{
962 VASurfaceAttrib va_attribs[2];
963 VASurfaceAttribExternalBuffers va_attrib_extbuf;
964 VAStatus status;
965
966 unsigned long buffer_fd = prime_fd;
967
968 va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
969 va_attrib_extbuf.width = r->width;
970 va_attrib_extbuf.height = r->height;
971 va_attrib_extbuf.data_size = r->height * stride;
972 va_attrib_extbuf.num_planes = 1;
973 va_attrib_extbuf.pitches[0] = stride;
974 va_attrib_extbuf.offsets[0] = 0;
975 va_attrib_extbuf.buffers = &buffer_fd;
976 va_attrib_extbuf.num_buffers = 1;
977 va_attrib_extbuf.flags = 0;
978 va_attrib_extbuf.private_data = NULL;
979
980 va_attribs[0].type = VASurfaceAttribMemoryType;
981 va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
982 va_attribs[0].value.type = VAGenericValueTypeInteger;
983 va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
984
985 va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
986 va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
987 va_attribs[1].value.type = VAGenericValueTypePointer;
988 va_attribs[1].value.value.p = &va_attrib_extbuf;
989
990 status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
991 r->width, r->height, surface, 1,
992 va_attribs, 2);
993
994 return status;
995}
996
997static VAStatus
998convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
999{
1000 VAProcPipelineParameterBuffer *pipeline_param;
1001 VAStatus status;
1002
1003 status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
1004 (void **) &pipeline_param);
1005 if (status != VA_STATUS_SUCCESS)
1006 return status;
1007
1008 memset(pipeline_param, 0, sizeof *pipeline_param);
1009
1010 pipeline_param->surface = rgb_surface;
1011 pipeline_param->surface_color_standard = VAProcColorStandardNone;
1012
1013 pipeline_param->output_background_color = 0xff000000;
1014 pipeline_param->output_color_standard = VAProcColorStandardNone;
1015
1016 status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
1017 if (status != VA_STATUS_SUCCESS)
1018 return status;
1019
1020 status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
1021 if (status != VA_STATUS_SUCCESS)
1022 return status;
1023
1024 status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
1025 &r->vpp.pipeline_buf, 1);
1026 if (status != VA_STATUS_SUCCESS)
1027 return status;
1028
1029 status = vaEndPicture(r->va_dpy, r->vpp.ctx);
1030 if (status != VA_STATUS_SUCCESS)
1031 return status;
1032
1033 return status;
1034}
1035
1036void
1037vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd,
1038 int stride)
1039{
1040 VASurfaceID rgb_surface;
1041 VAStatus status;
1042
1043 status = create_surface_from_fd(r, prime_fd, stride, &rgb_surface);
1044 if (status != VA_STATUS_SUCCESS) {
1045 weston_log("[libva recorder] "
1046 "failed to create surface from bo\n");
1047 return;
1048 }
1049
1050 status = convert_rgb_to_yuv(r, rgb_surface);
1051 if (status != VA_STATUS_SUCCESS) {
1052 weston_log("[libva recorder] "
1053 "color space conversion failed\n");
1054 return;
1055 }
1056
1057 encoder_encode(r, r->vpp.output);
1058
1059 vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
1060}
1061
1062