You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					1162 lines
				
				27 KiB
			
		
		
			
		
	
	
					1162 lines
				
				27 KiB
			| 
								 
											12 years ago
										 
									 | 
							
								/*
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
								 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								 * Copyright © 2013 Intel Corporation
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
								 * Permission is hereby granted, free of charge, to any person obtaining
							 | 
						||
| 
								 | 
							
								 * a copy of this software and associated documentation files (the
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								 * "Software"), to deal in the Software without restriction, including
							 | 
						||
| 
								 | 
							
								 * without limitation the rights to use, copy, modify, merge, publish,
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
								 * distribute, sublicense, and/or sell copies of the Software, and to
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								 * permit persons to whom the Software is furnished to do so, subject to
							 | 
						||
| 
								 | 
							
								 * the following conditions:
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * The above copyright notice and this permission notice (including the
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
								 * next paragraph) shall be included in all copies or substantial
							 | 
						||
| 
								 | 
							
								 * portions of the Software.
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								 *
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
								 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
							 | 
						||
| 
								 | 
							
								 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
							 | 
						||
| 
								 | 
							
								 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
							 | 
						||
| 
								 | 
							
								 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
							 | 
						||
| 
								 | 
							
								 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
							 | 
						||
| 
								 | 
							
								 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
							 | 
						||
| 
								 | 
							
								 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
							 | 
						||
| 
								 | 
							
								 * SOFTWARE.
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								#include "config.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stdint.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								#include <assert.h>
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								#include <errno.h>
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <sys/types.h>
							 | 
						||
| 
								 | 
							
								#include <sys/stat.h>
							 | 
						||
| 
								 | 
							
								#include <fcntl.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								#include <pthread.h>
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <va/va.h>
							 | 
						||
| 
								 | 
							
								#include <va/va_drm.h>
							 | 
						||
| 
								 | 
							
								#include <va/va_drmcommon.h>
							 | 
						||
| 
								 | 
							
								#include <va/va_enc_h264.h>
							 | 
						||
| 
								 | 
							
								#include <va/va_vpp.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "compositor.h"
							 | 
						||
| 
								 | 
							
								#include "vaapi-recorder.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define NAL_REF_IDC_NONE        0
							 | 
						||
| 
								 | 
							
								#define NAL_REF_IDC_LOW         1
							 | 
						||
| 
								 | 
							
								#define NAL_REF_IDC_MEDIUM      2
							 | 
						||
| 
								 | 
							
								#define NAL_REF_IDC_HIGH        3
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define NAL_NON_IDR             1
							 | 
						||
| 
								 | 
							
								#define NAL_IDR                 5
							 | 
						||
| 
								 | 
							
								#define NAL_SPS                 7
							 | 
						||
| 
								 | 
							
								#define NAL_PPS                 8
							 | 
						||
| 
								 | 
							
								#define NAL_SEI                 6
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define SLICE_TYPE_P            0
							 | 
						||
| 
								 | 
							
								#define SLICE_TYPE_B            1
							 | 
						||
| 
								 | 
							
								#define SLICE_TYPE_I            2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ENTROPY_MODE_CAVLC      0
							 | 
						||
| 
								 | 
							
								#define ENTROPY_MODE_CABAC      1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PROFILE_IDC_BASELINE    66
							 | 
						||
| 
								 | 
							
								#define PROFILE_IDC_MAIN        77
							 | 
						||
| 
								 | 
							
								#define PROFILE_IDC_HIGH        100
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct vaapi_recorder {
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int drm_fd, output_fd;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int width, height;
							 | 
						||
| 
								 | 
							
									int frame_count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int error;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int destroying;
							 | 
						||
| 
								 | 
							
									pthread_t worker_thread;
							 | 
						||
| 
								 | 
							
									pthread_mutex_t mutex;
							 | 
						||
| 
								 | 
							
									pthread_cond_t input_cond;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									struct {
							 | 
						||
| 
								 | 
							
										int valid;
							 | 
						||
| 
								 | 
							
										int prime_fd, stride;
							 | 
						||
| 
								 | 
							
									} input;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									VADisplay va_dpy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* video post processing is used for colorspace conversion */
							 | 
						||
| 
								 | 
							
									struct {
							 | 
						||
| 
								 | 
							
										VAConfigID cfg;
							 | 
						||
| 
								 | 
							
										VAContextID ctx;
							 | 
						||
| 
								 | 
							
										VABufferID pipeline_buf;
							 | 
						||
| 
								 | 
							
										VASurfaceID output;
							 | 
						||
| 
								 | 
							
									} vpp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									struct {
							 | 
						||
| 
								 | 
							
										VAConfigID cfg;
							 | 
						||
| 
								 | 
							
										VAContextID ctx;
							 | 
						||
| 
								 | 
							
										VASurfaceID reference_picture[3];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										int intra_period;
							 | 
						||
| 
								 | 
							
										int output_size;
							 | 
						||
| 
								 | 
							
										int constraint_set_flag;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										struct {
							 | 
						||
| 
								 | 
							
											VAEncSequenceParameterBufferH264 seq;
							 | 
						||
| 
								 | 
							
											VAEncPictureParameterBufferH264 pic;
							 | 
						||
| 
								 | 
							
											VAEncSliceParameterBufferH264 slice;
							 | 
						||
| 
								 | 
							
										} param;
							 | 
						||
| 
								 | 
							
									} encoder;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								static void *
							 | 
						||
| 
								 | 
							
								worker_thread_function(void *);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								/* bistream code used for writing the packed headers */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define BITSTREAM_ALLOCATE_STEPPING	 4096
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct bitstream {
							 | 
						||
| 
								 | 
							
									unsigned int *buffer;
							 | 
						||
| 
								 | 
							
									int bit_offset;
							 | 
						||
| 
								 | 
							
									int max_size_in_dword;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static unsigned int
							 | 
						||
| 
								 | 
							
								va_swap32(unsigned int val)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned char *pval = (unsigned char *)&val;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ((pval[0] << 24) |
							 | 
						||
| 
								 | 
							
										(pval[1] << 16) |
							 | 
						||
| 
								 | 
							
										(pval[2] << 8)  |
							 | 
						||
| 
								 | 
							
										(pval[3] << 0));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_start(struct bitstream *bs)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
							 | 
						||
| 
								 
											10 years ago
										 
									 | 
							
									bs->buffer = calloc(bs->max_size_in_dword * sizeof(unsigned int), 1);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									bs->bit_offset = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_end(struct bitstream *bs)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int pos = (bs->bit_offset >> 5);
							 | 
						||
| 
								 | 
							
									int bit_offset = (bs->bit_offset & 0x1f);
							 | 
						||
| 
								 | 
							
									int bit_left = 32 - bit_offset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (bit_offset) {
							 | 
						||
| 
								 | 
							
										bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_put_ui(struct bitstream *bs, unsigned int val, int size_in_bits)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int pos = (bs->bit_offset >> 5);
							 | 
						||
| 
								 | 
							
									int bit_offset = (bs->bit_offset & 0x1f);
							 | 
						||
| 
								 | 
							
									int bit_left = 32 - bit_offset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!size_in_bits)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bs->bit_offset += size_in_bits;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (bit_left > size_in_bits) {
							 | 
						||
| 
								 | 
							
										bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									size_in_bits -= bit_left;
							 | 
						||
| 
								 | 
							
									bs->buffer[pos] =
							 | 
						||
| 
								 | 
							
										(bs->buffer[pos] << bit_left) | (val >> size_in_bits);
							 | 
						||
| 
								 | 
							
									bs->buffer[pos] = va_swap32(bs->buffer[pos]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pos + 1 == bs->max_size_in_dword) {
							 | 
						||
| 
								 | 
							
										bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
							 | 
						||
| 
								 | 
							
										bs->buffer =
							 | 
						||
| 
								 | 
							
											realloc(bs->buffer,
							 | 
						||
| 
								 | 
							
												bs->max_size_in_dword * sizeof(unsigned int));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bs->buffer[pos + 1] = val;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_put_ue(struct bitstream *bs, unsigned int val)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int size_in_bits = 0;
							 | 
						||
| 
								 | 
							
									int tmp_val = ++val;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (tmp_val) {
							 | 
						||
| 
								 | 
							
										tmp_val >>= 1;
							 | 
						||
| 
								 | 
							
										size_in_bits++;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											10 years ago
										 
									 | 
							
									bitstream_put_ui(bs, 0, size_in_bits - 1); /* leading zero */
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									bitstream_put_ui(bs, val, size_in_bits);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_put_se(struct bitstream *bs, int val)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int new_val;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (val <= 0)
							 | 
						||
| 
								 | 
							
										new_val = -2 * val;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										new_val = 2 * val - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, new_val);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								bitstream_byte_aligning(struct bitstream *bs, int bit)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int bit_offset = (bs->bit_offset & 0x7);
							 | 
						||
| 
								 | 
							
									int bit_left = 8 - bit_offset;
							 | 
						||
| 
								 | 
							
									int new_val;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!bit_offset)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (bit)
							 | 
						||
| 
								 | 
							
										new_val = (1 << bit_left) - 1;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										new_val = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, new_val, bit_left);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VAStatus
							 | 
						||
| 
								 | 
							
								encoder_create_config(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAConfigAttrib attrib[2];
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* FIXME: should check if VAEntrypointEncSlice is supported */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* FIXME: should check if specified attributes are supported */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									attrib[0].type = VAConfigAttribRTFormat;
							 | 
						||
| 
								 | 
							
									attrib[0].value = VA_RT_FORMAT_YUV420;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									attrib[1].type = VAConfigAttribRateControl;
							 | 
						||
| 
								 | 
							
									attrib[1].value = VA_RC_CQP;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateConfig(r->va_dpy, VAProfileH264Main,
							 | 
						||
| 
								 | 
							
												VAEntrypointEncSlice, attrib, 2,
							 | 
						||
| 
								 | 
							
												&r->encoder.cfg);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateContext(r->va_dpy, r->encoder.cfg,
							 | 
						||
| 
								 | 
							
												 r->width, r->height, VA_PROGRESSIVE, 0, 0,
							 | 
						||
| 
								 | 
							
												 &r->encoder.ctx);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										vaDestroyConfig(r->va_dpy, r->encoder.cfg);
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return VA_STATUS_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								encoder_destroy_config(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									vaDestroyContext(r->va_dpy, r->encoder.ctx);
							 | 
						||
| 
								 | 
							
									vaDestroyConfig(r->va_dpy, r->encoder.cfg);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								encoder_init_seq_parameters(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int width_in_mbs, height_in_mbs;
							 | 
						||
| 
								 | 
							
									int frame_cropping_flag = 0;
							 | 
						||
| 
								 | 
							
									int frame_crop_bottom_offset = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									width_in_mbs = (r->width + 15) / 16;
							 | 
						||
| 
								 | 
							
									height_in_mbs = (r->height + 15) / 16;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.level_idc = 41;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.intra_period = r->encoder.intra_period;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.max_num_ref_frames = 4;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.picture_width_in_mbs = width_in_mbs;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.picture_height_in_mbs = height_in_mbs;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.seq_fields.bits.frame_mbs_only_flag = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Tc = num_units_in_tick / time_scale */
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.time_scale = 1800;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.num_units_in_tick = 15;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (height_in_mbs * 16 - r->height > 0) {
							 | 
						||
| 
								 | 
							
										frame_cropping_flag = 1;
							 | 
						||
| 
								 | 
							
										frame_crop_bottom_offset = (height_in_mbs * 16 - r->height) / 2;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.frame_cropping_flag = frame_cropping_flag;
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.frame_crop_bottom_offset = frame_crop_bottom_offset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.param.seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VABufferID
							 | 
						||
| 
								 | 
							
								encoder_update_seq_parameters(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VABufferID seq_buf;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncSequenceParameterBufferType,
							 | 
						||
| 
								 | 
							
												sizeof(r->encoder.param.seq),
							 | 
						||
| 
								 | 
							
												1, &r->encoder.param.seq,
							 | 
						||
| 
								 | 
							
												&seq_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (status == VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return seq_buf;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								encoder_init_pic_parameters(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pic->pic_init_qp = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* ENTROPY_MODE_CABAC */
							 | 
						||
| 
								 | 
							
									pic->pic_fields.bits.entropy_coding_mode_flag = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pic->pic_fields.bits.deblocking_filter_control_present_flag = 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VABufferID
							 | 
						||
| 
								 | 
							
								encoder_update_pic_parameters(struct vaapi_recorder *r,
							 | 
						||
| 
								 | 
							
											      VABufferID output_buf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
									VABufferID pic_param_buf;
							 | 
						||
| 
								 | 
							
									VASurfaceID curr_pic, pic0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									curr_pic = r->encoder.reference_picture[r->frame_count % 2];
							 | 
						||
| 
								 | 
							
									pic0 = r->encoder.reference_picture[(r->frame_count + 1) % 2];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pic->CurrPic.picture_id = curr_pic;
							 | 
						||
| 
								 | 
							
									pic->CurrPic.TopFieldOrderCnt = r->frame_count * 2;
							 | 
						||
| 
								 | 
							
									pic->ReferenceFrames[0].picture_id = pic0;
							 | 
						||
| 
								 | 
							
									pic->ReferenceFrames[1].picture_id = r->encoder.reference_picture[2];
							 | 
						||
| 
								 | 
							
									pic->ReferenceFrames[2].picture_id = VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pic->coded_buf = output_buf;
							 | 
						||
| 
								 | 
							
									pic->frame_num = r->frame_count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pic->pic_fields.bits.idr_pic_flag = (r->frame_count == 0);
							 | 
						||
| 
								 | 
							
									pic->pic_fields.bits.reference_pic_flag = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncPictureParameterBufferType,
							 | 
						||
| 
								 | 
							
												sizeof(VAEncPictureParameterBufferH264), 1,
							 | 
						||
| 
								 | 
							
												pic, &pic_param_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (status == VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return pic_param_buf;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VABufferID
							 | 
						||
| 
								 | 
							
								encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VABufferID slice_param_buf;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int width_in_mbs = (r->width + 15) / 16;
							 | 
						||
| 
								 | 
							
									int height_in_mbs = (r->height + 15) / 16;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									memset(&r->encoder.param.slice, 0, sizeof r->encoder.param.slice);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.param.slice.num_macroblocks = width_in_mbs * height_in_mbs;
							 | 
						||
| 
								 | 
							
									r->encoder.param.slice.slice_type = slice_type;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.param.slice.slice_alpha_c0_offset_div2 = 2;
							 | 
						||
| 
								 | 
							
									r->encoder.param.slice.slice_beta_offset_div2 = 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncSliceParameterBufferType,
							 | 
						||
| 
								 | 
							
												sizeof(r->encoder.param.slice), 1,
							 | 
						||
| 
								 | 
							
												&r->encoder.param.slice,
							 | 
						||
| 
								 | 
							
												&slice_param_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (status == VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return slice_param_buf;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VABufferID
							 | 
						||
| 
								 | 
							
								encoder_update_misc_hdr_parameter(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAEncMiscParameterBuffer *misc_param;
							 | 
						||
| 
								 | 
							
									VAEncMiscParameterHRD *hrd;
							 | 
						||
| 
								 | 
							
									VABufferID buffer;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int total_size =
							 | 
						||
| 
								 | 
							
										sizeof(VAEncMiscParameterBuffer) +
							 | 
						||
| 
								 | 
							
										sizeof(VAEncMiscParameterRateControl);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncMiscParameterBufferType, total_size,
							 | 
						||
| 
								 | 
							
												1, NULL, &buffer);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaMapBuffer(r->va_dpy, buffer, (void **) &misc_param);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, buffer);
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									misc_param->type = VAEncMiscParameterTypeHRD;
							 | 
						||
| 
								 | 
							
									hrd = (VAEncMiscParameterHRD *) misc_param->data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									hrd->initial_buffer_fullness = 0;
							 | 
						||
| 
								 | 
							
									hrd->buffer_size = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									vaUnmapBuffer(r->va_dpy, buffer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return buffer;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								setup_encoder(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = encoder_create_config(r);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
							 | 
						||
| 
								 | 
							
												  r->width, r->height,
							 | 
						||
| 
								 | 
							
												  r->encoder.reference_picture, 3,
							 | 
						||
| 
								 | 
							
												  NULL, 0);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										encoder_destroy_config(r);
							 | 
						||
| 
								 | 
							
										return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* VAProfileH264Main */
							 | 
						||
| 
								 | 
							
									r->encoder.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.output_size = r->width * r->height;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->encoder.intra_period = 30;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									encoder_init_seq_parameters(r);
							 | 
						||
| 
								 | 
							
									encoder_init_pic_parameters(r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								encoder_destroy(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									encoder_destroy_config(r);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								nal_start_code_prefix(struct bitstream *bs)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0x00000001, 32);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								nal_header(struct bitstream *bs, int nal_ref_idc, int nal_unit_type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									/* forbidden_zero_bit: 0 */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, nal_ref_idc, 2);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, nal_unit_type, 5);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								rbsp_trailing_bits(struct bitstream *bs)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 1, 1);
							 | 
						||
| 
								 | 
							
									bitstream_byte_aligning(bs, 0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void sps_rbsp(struct bitstream *bs,
							 | 
						||
| 
								 | 
							
										     VAEncSequenceParameterBufferH264 *seq,
							 | 
						||
| 
								 | 
							
										     int constraint_set_flag)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, PROFILE_IDC_MAIN, 8);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* constraint_set[0-3] flag */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < 4; i++) {
							 | 
						||
| 
								 | 
							
										int set = (constraint_set_flag & (1 << i)) ? 1 : 0;
							 | 
						||
| 
								 | 
							
										bitstream_put_ui(bs, set, 1);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* reserved_zero_4bits */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 4);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->level_idc, 8);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->seq_parameter_set_id);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->seq_fields.bits.log2_max_frame_num_minus4);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->seq_fields.bits.pic_order_cnt_type);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs,
							 | 
						||
| 
								 | 
							
											 seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->max_num_ref_frames);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* gaps_in_frame_num_value_allowed_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->picture_width_in_mbs - 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, seq->picture_height_in_mbs - 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->seq_fields.bits.frame_mbs_only_flag, 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->seq_fields.bits.direct_8x8_inference_flag, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->frame_cropping_flag, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (seq->frame_cropping_flag) {
							 | 
						||
| 
								 | 
							
										bitstream_put_ue(bs, seq->frame_crop_left_offset);
							 | 
						||
| 
								 | 
							
										bitstream_put_ue(bs, seq->frame_crop_right_offset);
							 | 
						||
| 
								 | 
							
										bitstream_put_ue(bs, seq->frame_crop_top_offset);
							 | 
						||
| 
								 | 
							
										bitstream_put_ue(bs, seq->frame_crop_bottom_offset);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* vui_parameters_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 1, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* aspect_ratio_info_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
									/* overscan_info_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* video_signal_type_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
									/* chroma_loc_info_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* timing_info_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 1, 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->num_units_in_tick, 32);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, seq->time_scale, 32);
							 | 
						||
| 
								 | 
							
									/* fixed_frame_rate_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 1, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* nal_hrd_parameters_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* vcl_hrd_parameters_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* low_delay_hrd_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pic_struct_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
									/* bitstream_restriction_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									rbsp_trailing_bits(bs);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void pps_rbsp(struct bitstream *bs,
							 | 
						||
| 
								 | 
							
										     VAEncPictureParameterBufferH264 *pic)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									/* pic_parameter_set_id, seq_parameter_set_id */
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, pic->pic_parameter_set_id);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, pic->seq_parameter_set_id);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, pic->pic_fields.bits.entropy_coding_mode_flag, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pic_order_present_flag: 0 */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* num_slice_groups_minus1 */
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, pic->num_ref_idx_l0_active_minus1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ue(bs, pic->num_ref_idx_l1_active_minus1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, pic->pic_fields.bits.weighted_pred_flag, 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, pic->pic_fields.bits.weighted_bipred_idc, 2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */
							 | 
						||
| 
								 | 
							
									bitstream_put_se(bs, pic->pic_init_qp - 26);
							 | 
						||
| 
								 | 
							
									bitstream_put_se(bs, 0);
							 | 
						||
| 
								 | 
							
									bitstream_put_se(bs, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, pic->pic_fields.bits.deblocking_filter_control_present_flag, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, pic->pic_fields.bits.transform_8x8_mode_flag, 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pic_scaling_matrix_present_flag */
							 | 
						||
| 
								 | 
							
									bitstream_put_ui(bs, 0, 1);
							 | 
						||
| 
								 | 
							
									bitstream_put_se(bs, pic->second_chroma_qp_index_offset );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									rbsp_trailing_bits(bs);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								build_packed_pic_buffer(struct vaapi_recorder *r,
							 | 
						||
| 
								 | 
							
											void **header_buffer)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct bitstream bs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_start(&bs);
							 | 
						||
| 
								 | 
							
									nal_start_code_prefix(&bs);
							 | 
						||
| 
								 | 
							
									nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
							 | 
						||
| 
								 | 
							
									pps_rbsp(&bs, &r->encoder.param.pic);
							 | 
						||
| 
								 | 
							
									bitstream_end(&bs);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									*header_buffer = bs.buffer;
							 | 
						||
| 
								 | 
							
									return bs.bit_offset;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								build_packed_seq_buffer(struct vaapi_recorder *r,
							 | 
						||
| 
								 | 
							
											void **header_buffer)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct bitstream bs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bitstream_start(&bs);
							 | 
						||
| 
								 | 
							
									nal_start_code_prefix(&bs);
							 | 
						||
| 
								 | 
							
									nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
							 | 
						||
| 
								 | 
							
									sps_rbsp(&bs, &r->encoder.param.seq, r->encoder.constraint_set_flag);
							 | 
						||
| 
								 | 
							
									bitstream_end(&bs);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									*header_buffer = bs.buffer;
							 | 
						||
| 
								 | 
							
									return bs.bit_offset;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								create_packed_header_buffers(struct vaapi_recorder *r, VABufferID *buffers,
							 | 
						||
| 
								 | 
							
											     VAEncPackedHeaderType type,
							 | 
						||
| 
								 | 
							
											     void *data, int bit_length)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAEncPackedHeaderParameterBuffer packed_header;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									packed_header.type = type;
							 | 
						||
| 
								 | 
							
									packed_header.bit_length = bit_length;
							 | 
						||
| 
								 | 
							
									packed_header.has_emulation_bytes = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncPackedHeaderParameterBufferType,
							 | 
						||
| 
								 | 
							
												sizeof packed_header, 1, &packed_header,
							 | 
						||
| 
								 | 
							
												&buffers[0]);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncPackedHeaderDataBufferType,
							 | 
						||
| 
								 | 
							
												(bit_length + 7) / 8, 1, data, &buffers[1]);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, buffers[0]);
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 2;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								encoder_prepare_headers(struct vaapi_recorder *r, VABufferID *buffers)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VABufferID *p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int bit_length;
							 | 
						||
| 
								 | 
							
									void *data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									p = buffers;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bit_length = build_packed_seq_buffer(r, &data);
							 | 
						||
| 
								 | 
							
									p += create_packed_header_buffers(r, p, VAEncPackedHeaderSequence,
							 | 
						||
| 
								 | 
							
													  data, bit_length);
							 | 
						||
| 
								 | 
							
									free(data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bit_length = build_packed_pic_buffer(r, &data);
							 | 
						||
| 
								 | 
							
									p += create_packed_header_buffers(r, p, VAEncPackedHeaderPicture,
							 | 
						||
| 
								 | 
							
													  data, bit_length);
							 | 
						||
| 
								 | 
							
									free(data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return p - buffers;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VAStatus
							 | 
						||
| 
								 | 
							
								encoder_render_picture(struct vaapi_recorder *r, VASurfaceID input,
							 | 
						||
| 
								 | 
							
										       VABufferID *buffers, int count)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaBeginPicture(r->va_dpy, r->encoder.ctx, input);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaRenderPicture(r->va_dpy, r->encoder.ctx, buffers, count);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaEndPicture(r->va_dpy, r->encoder.ctx);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return vaSyncSurface(r->va_dpy, input);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VABufferID
							 | 
						||
| 
								 | 
							
								encoder_create_output_buffer(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VABufferID output_buf;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
							 | 
						||
| 
								 | 
							
												VAEncCodedBufferType, r->encoder.output_size,
							 | 
						||
| 
								 | 
							
												1, NULL, &output_buf);
							 | 
						||
| 
								 | 
							
									if (status == VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return output_buf;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										return VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								enum output_write_status {
							 | 
						||
| 
								 | 
							
									OUTPUT_WRITE_SUCCESS,
							 | 
						||
| 
								 | 
							
									OUTPUT_WRITE_OVERFLOW,
							 | 
						||
| 
								 | 
							
									OUTPUT_WRITE_FATAL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static enum output_write_status
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VACodedBufferSegment *segment;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
									int count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
										return OUTPUT_WRITE_FATAL;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
									if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
							 | 
						||
| 
								 | 
							
										r->encoder.output_size *= 2;
							 | 
						||
| 
								 | 
							
										vaUnmapBuffer(r->va_dpy, output_buf);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
										return OUTPUT_WRITE_OVERFLOW;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									count = write(r->output_fd, segment->buf, segment->size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									vaUnmapBuffer(r->va_dpy, output_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									if (count < 0)
							 | 
						||
| 
								 | 
							
										return OUTPUT_WRITE_FATAL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return OUTPUT_WRITE_SUCCESS;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VABufferID output_buf = VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									VABufferID buffers[8];
							 | 
						||
| 
								 | 
							
									int count = 0;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int i, slice_type;
							 | 
						||
| 
								 | 
							
									enum output_write_status ret;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
									if ((r->frame_count % r->encoder.intra_period) == 0)
							 | 
						||
| 
								 | 
							
										slice_type = SLICE_TYPE_I;
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										slice_type = SLICE_TYPE_P;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									buffers[count++] = encoder_update_seq_parameters(r);
							 | 
						||
| 
								 | 
							
									buffers[count++] = encoder_update_misc_hdr_parameter(r);
							 | 
						||
| 
								 | 
							
									buffers[count++] = encoder_update_slice_parameter(r, slice_type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < count; i++)
							 | 
						||
| 
								 | 
							
										if (buffers[i] == VA_INVALID_ID)
							 | 
						||
| 
								 | 
							
											goto bail;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (r->frame_count == 0)
							 | 
						||
| 
								 | 
							
										count += encoder_prepare_headers(r, buffers + count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									do {
							 | 
						||
| 
								 | 
							
										output_buf = encoder_create_output_buffer(r);
							 | 
						||
| 
								 | 
							
										if (output_buf == VA_INVALID_ID)
							 | 
						||
| 
								 | 
							
											goto bail;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										buffers[count++] =
							 | 
						||
| 
								 | 
							
											encoder_update_pic_parameters(r, output_buf);
							 | 
						||
| 
								 | 
							
										if (buffers[count - 1] == VA_INVALID_ID)
							 | 
						||
| 
								 | 
							
											goto bail;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										encoder_render_picture(r, input, buffers, count);
							 | 
						||
| 
								 | 
							
										ret = encoder_write_output(r, output_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, output_buf);
							 | 
						||
| 
								 | 
							
										output_buf = VA_INVALID_ID;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, buffers[--count]);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									} while (ret == OUTPUT_WRITE_OVERFLOW);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (ret == OUTPUT_WRITE_FATAL)
							 | 
						||
| 
								 | 
							
										r->error = errno;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < count; i++)
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, buffers[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->frame_count++;
							 | 
						||
| 
								 | 
							
									return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bail:
							 | 
						||
| 
								 | 
							
									for (i = 0; i < count; i++)
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, buffers[i]);
							 | 
						||
| 
								 | 
							
									if (output_buf != VA_INVALID_ID)
							 | 
						||
| 
								 | 
							
										vaDestroyBuffer(r->va_dpy, output_buf);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								setup_vpp(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateConfig(r->va_dpy, VAProfileNone,
							 | 
						||
| 
								 | 
							
												VAEntrypointVideoProc, NULL, 0,
							 | 
						||
| 
								 | 
							
												&r->vpp.cfg);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to create VPP config\n");
							 | 
						||
| 
								 | 
							
										return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
							 | 
						||
| 
								 | 
							
												 0, NULL, 0, &r->vpp.ctx);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to create VPP context\n");
							 | 
						||
| 
								 | 
							
										goto err_cfg;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
							 | 
						||
| 
								 | 
							
												VAProcPipelineParameterBufferType,
							 | 
						||
| 
								 | 
							
												sizeof(VAProcPipelineParameterBuffer),
							 | 
						||
| 
								 | 
							
												1, NULL, &r->vpp.pipeline_buf);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to create VPP pipeline buffer\n");
							 | 
						||
| 
								 | 
							
										goto err_ctx;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
							 | 
						||
| 
								 | 
							
												  r->width, r->height, &r->vpp.output, 1,
							 | 
						||
| 
								 | 
							
												  NULL, 0);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to create YUV surface\n");
							 | 
						||
| 
								 | 
							
										goto err_buf;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								err_buf:
							 | 
						||
| 
								 | 
							
									vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
							 | 
						||
| 
								 | 
							
								err_ctx:
							 | 
						||
| 
								 | 
							
									vaDestroyConfig(r->va_dpy, r->vpp.ctx);
							 | 
						||
| 
								 | 
							
								err_cfg:
							 | 
						||
| 
								 | 
							
									vaDestroyConfig(r->va_dpy, r->vpp.cfg);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								vpp_destroy(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
							 | 
						||
| 
								 | 
							
									vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
							 | 
						||
| 
								 | 
							
									vaDestroyConfig(r->va_dpy, r->vpp.ctx);
							 | 
						||
| 
								 | 
							
									vaDestroyConfig(r->va_dpy, r->vpp.cfg);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								static int
							 | 
						||
| 
								 | 
							
								setup_worker_thread(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									pthread_mutex_init(&r->mutex, NULL);
							 | 
						||
| 
								 | 
							
									pthread_cond_init(&r->input_cond, NULL);
							 | 
						||
| 
								 | 
							
									pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								destroy_worker_thread(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									pthread_mutex_lock(&r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Make sure the worker thread finishes */
							 | 
						||
| 
								 | 
							
									r->destroying = 1;
							 | 
						||
| 
								 | 
							
									pthread_cond_signal(&r->input_cond);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthread_mutex_unlock(&r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthread_join(r->worker_thread, NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthread_mutex_destroy(&r->mutex);
							 | 
						||
| 
								 | 
							
									pthread_cond_destroy(&r->input_cond);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								struct vaapi_recorder *
							 | 
						||
| 
								 | 
							
								vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct vaapi_recorder *r;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
									int major, minor;
							 | 
						||
| 
								 | 
							
									int flags;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											11 years ago
										 
									 | 
							
									r = zalloc(sizeof *r);
							 | 
						||
| 
								 | 
							
									if (r == NULL)
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									r->width = width;
							 | 
						||
| 
								 | 
							
									r->height = height;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									r->drm_fd = drm_fd;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									if (setup_worker_thread(r) < 0)
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
										goto err_free;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
							 | 
						||
| 
								 | 
							
									r->output_fd = open(filename, flags, 0644);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									if (r->output_fd < 0)
							 | 
						||
| 
								 | 
							
										goto err_thread;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									r->va_dpy = vaGetDisplayDRM(drm_fd);
							 | 
						||
| 
								 | 
							
									if (!r->va_dpy) {
							 | 
						||
| 
								 | 
							
										weston_log("failed to create VA display\n");
							 | 
						||
| 
								 | 
							
										goto err_fd;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaInitialize(r->va_dpy, &major, &minor);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to initialize display\n");
							 | 
						||
| 
								 | 
							
										goto err_fd;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (setup_vpp(r) < 0) {
							 | 
						||
| 
								 | 
							
										weston_log("vaapi: failed to initialize VPP pipeline\n");
							 | 
						||
| 
								 | 
							
										goto err_va_dpy;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (setup_encoder(r) < 0) {
							 | 
						||
| 
								 | 
							
										goto err_vpp;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return r;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								err_vpp:
							 | 
						||
| 
								 | 
							
									vpp_destroy(r);
							 | 
						||
| 
								 | 
							
								err_va_dpy:
							 | 
						||
| 
								 | 
							
									vaTerminate(r->va_dpy);
							 | 
						||
| 
								 | 
							
								err_fd:
							 | 
						||
| 
								 | 
							
									close(r->output_fd);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								err_thread:
							 | 
						||
| 
								 | 
							
									destroy_worker_thread(r);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								err_free:
							 | 
						||
| 
								 | 
							
									free(r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								vaapi_recorder_destroy(struct vaapi_recorder *r)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									destroy_worker_thread(r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									encoder_destroy(r);
							 | 
						||
| 
								 | 
							
									vpp_destroy(r);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									vaTerminate(r->va_dpy);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									close(r->output_fd);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									close(r->drm_fd);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
									free(r);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VAStatus
							 | 
						||
| 
								 | 
							
								create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
							 | 
						||
| 
								 | 
							
										       int stride, VASurfaceID *surface)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VASurfaceAttrib va_attribs[2];
							 | 
						||
| 
								 | 
							
									VASurfaceAttribExternalBuffers va_attrib_extbuf;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									unsigned long buffer_fd = prime_fd;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.width = r->width;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.height = r->height;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.data_size = r->height * stride;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.num_planes = 1;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.pitches[0] = stride;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.offsets[0] = 0;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.buffers = &buffer_fd;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.num_buffers = 1;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.flags = 0;
							 | 
						||
| 
								 | 
							
									va_attrib_extbuf.private_data = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									va_attribs[0].type = VASurfaceAttribMemoryType;
							 | 
						||
| 
								 | 
							
									va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
							 | 
						||
| 
								 | 
							
									va_attribs[0].value.type = VAGenericValueTypeInteger;
							 | 
						||
| 
								 | 
							
									va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
							 | 
						||
| 
								 | 
							
									va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
							 | 
						||
| 
								 | 
							
									va_attribs[1].value.type = VAGenericValueTypePointer;
							 | 
						||
| 
								 | 
							
									va_attribs[1].value.value.p = &va_attrib_extbuf;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
							 | 
						||
| 
								 | 
							
												  r->width, r->height, surface, 1,
							 | 
						||
| 
								 | 
							
												  va_attribs, 2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return status;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static VAStatus
							 | 
						||
| 
								 | 
							
								convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									VAProcPipelineParameterBuffer *pipeline_param;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
							 | 
						||
| 
								 | 
							
											     (void **) &pipeline_param);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									memset(pipeline_param, 0, sizeof *pipeline_param);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pipeline_param->surface = rgb_surface;
							 | 
						||
| 
								 | 
							
									pipeline_param->surface_color_standard  = VAProcColorStandardNone;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pipeline_param->output_background_color = 0xff000000;
							 | 
						||
| 
								 | 
							
									pipeline_param->output_color_standard   = VAProcColorStandardNone;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
							 | 
						||
| 
								 | 
							
												 &r->vpp.pipeline_buf, 1);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									status = vaEndPicture(r->va_dpy, r->vpp.ctx);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS)
							 | 
						||
| 
								 | 
							
										return status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return status;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								static void
							 | 
						||
| 
								 | 
							
								recorder_frame(struct vaapi_recorder *r)
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								{
							 | 
						||
| 
								 | 
							
									VASurfaceID rgb_surface;
							 | 
						||
| 
								 | 
							
									VAStatus status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									status = create_surface_from_fd(r, r->input.prime_fd,
							 | 
						||
| 
								 | 
							
													r->input.stride, &rgb_surface);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("[libva recorder] "
							 | 
						||
| 
								 | 
							
											   "failed to create surface from bo\n");
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									close(r->input.prime_fd);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									status = convert_rgb_to_yuv(r, rgb_surface);
							 | 
						||
| 
								 | 
							
									if (status != VA_STATUS_SUCCESS) {
							 | 
						||
| 
								 | 
							
										weston_log("[libva recorder] "
							 | 
						||
| 
								 | 
							
											   "color space conversion failed\n");
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									encoder_encode(r, r->vpp.output);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								static void *
							 | 
						||
| 
								 | 
							
								worker_thread_function(void *data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct vaapi_recorder *r = data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthread_mutex_lock(&r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (!r->destroying) {
							 | 
						||
| 
								 | 
							
										if (!r->input.valid)
							 | 
						||
| 
								 | 
							
											pthread_cond_wait(&r->input_cond, &r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* If the thread is awaken by destroy_worker_thread(),
							 | 
						||
| 
								 | 
							
										 * there might not be valid input */
							 | 
						||
| 
								 | 
							
										if (!r->input.valid)
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										recorder_frame(r);
							 | 
						||
| 
								 | 
							
										r->input.valid = 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pthread_mutex_unlock(&r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								int
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									int ret = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									pthread_mutex_lock(&r->mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									if (r->error) {
							 | 
						||
| 
								 | 
							
										errno = r->error;
							 | 
						||
| 
								 | 
							
										ret = -1;
							 | 
						||
| 
								 | 
							
										goto unlock;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									/* The mutex is never released while encoding, so this point should
							 | 
						||
| 
								 | 
							
									 * never be reached if input.valid is true. */
							 | 
						||
| 
								 | 
							
									assert(!r->input.valid);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									r->input.prime_fd = prime_fd;
							 | 
						||
| 
								 | 
							
									r->input.stride = stride;
							 | 
						||
| 
								 | 
							
									r->input.valid = 1;
							 | 
						||
| 
								 | 
							
									pthread_cond_signal(&r->input_cond);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								unlock:
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
									pthread_mutex_unlock(&r->mutex);
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
									return ret;
							 | 
						||
| 
								 
											12 years ago
										 
									 | 
							
								}
							 |