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