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