compositor-drm: Add hardware accelerated capture of screen using libva
[profile/ivi/weston-ivi-shell.git] / src / vaapi-recorder.c
1 /*
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
87 struct 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
123 struct bitstream {
124         unsigned int *buffer;
125         int bit_offset;
126         int max_size_in_dword;
127 };
128
129 static unsigned int
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
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(int), 1);
145         bs->bit_offset = 0;
146 }
147
148 static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
481 nal_start_code_prefix(struct bitstream *bs)
482 {
483         bitstream_put_ui(bs, 0x00000001, 32);
484 }
485
486 static void
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
497 rbsp_trailing_bits(struct bitstream *bs)
498 {
499         bitstream_put_ui(bs, 1, 1);
500         bitstream_byte_aligning(bs, 0);
501 }
502
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
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
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
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
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
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
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
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 static int
748 encoder_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
771 static void
772 encoder_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
823 bail:
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
831 static int
832 setup_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
870 err_buf:
871         vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
872 err_ctx:
873         vaDestroyConfig(r->va_dpy, r->vpp.ctx);
874 err_cfg:
875         vaDestroyConfig(r->va_dpy, r->vpp.cfg);
876
877         return -1;
878 }
879
880 static void
881 vpp_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
889 struct vaapi_recorder *
890 vaapi_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
933 err_vpp:
934         vpp_destroy(r);
935 err_va_dpy:
936         vaTerminate(r->va_dpy);
937 err_fd:
938         close(r->output_fd);
939 err_free:
940         free(r);
941
942         return NULL;
943 }
944
945 void
946 vaapi_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
958 static VAStatus
959 create_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
997 static VAStatus
998 convert_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
1036 void
1037 vaapi_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