]> git.sesse.net Git - ffmpeg/blob - libavcodec/vaapi.c
Add common VA API data structures and helpers.
[ffmpeg] / libavcodec / vaapi.c
1 /*
2  * Video Acceleration API (video decoding)
3  * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
4  *
5  * Copyright (C) 2008-2009 Splitted-Desktop Systems
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include "vaapi_internal.h"
25
26 /**
27  * \addtogroup VAAPI_Decoding
28  *
29  * @{
30  */
31
32 static void destroy_buffers(VADisplay display, VABufferID *buffers, unsigned int n_buffers)
33 {
34     unsigned int i;
35     for (i = 0; i < n_buffers; i++) {
36         if (buffers[i]) {
37             vaDestroyBuffer(display, buffers[i]);
38             buffers[i] = 0;
39         }
40     }
41 }
42
43 static int render_picture(struct vaapi_context *vactx, VASurfaceID surface)
44 {
45     VABufferID va_buffers[3];
46     unsigned int n_va_buffers = 0;
47
48     if (vaCreateBuffer(vactx->display, vactx->context_id,
49                        VAPictureParameterBufferType,
50                        vactx->pic_param_size,
51                        1, &vactx->pic_param,
52                        &vactx->pic_param_buf_id) != VA_STATUS_SUCCESS)
53         return -1;
54     va_buffers[n_va_buffers++] = vactx->pic_param_buf_id;
55
56     if (vactx->iq_matrix_present) {
57         if (vaCreateBuffer(vactx->display, vactx->context_id,
58                            VAIQMatrixBufferType,
59                            vactx->iq_matrix_size,
60                            1, &vactx->iq_matrix,
61                            &vactx->iq_matrix_buf_id) != VA_STATUS_SUCCESS)
62             return -1;
63         va_buffers[n_va_buffers++] = vactx->iq_matrix_buf_id;
64     }
65
66     if (vactx->bitplane_buffer) {
67         if (vaCreateBuffer(vactx->display, vactx->context_id,
68                            VABitPlaneBufferType,
69                            vactx->bitplane_buffer_size,
70                            1, vactx->bitplane_buffer,
71                            &vactx->bitplane_buf_id) != VA_STATUS_SUCCESS)
72             return -1;
73         va_buffers[n_va_buffers++] = vactx->bitplane_buf_id;
74     }
75
76     if (vaBeginPicture(vactx->display, vactx->context_id,
77                        surface) != VA_STATUS_SUCCESS)
78         return -1;
79
80     if (vaRenderPicture(vactx->display, vactx->context_id,
81                         va_buffers, n_va_buffers) != VA_STATUS_SUCCESS)
82         return -1;
83
84     if (vaRenderPicture(vactx->display, vactx->context_id,
85                         vactx->slice_buf_ids,
86                         vactx->n_slice_buf_ids) != VA_STATUS_SUCCESS)
87         return -1;
88
89     if (vaEndPicture(vactx->display, vactx->context_id) != VA_STATUS_SUCCESS)
90         return -1;
91
92     return 0;
93 }
94
95 static int commit_slices(struct vaapi_context *vactx)
96 {
97     VABufferID *slice_buf_ids;
98     VABufferID slice_param_buf_id, slice_data_buf_id;
99
100     if (vactx->slice_count == 0)
101         return 0;
102
103     slice_buf_ids =
104         av_fast_realloc(vactx->slice_buf_ids,
105                         &vactx->slice_buf_ids_alloc,
106                         (vactx->n_slice_buf_ids + 2) * sizeof(slice_buf_ids[0]));
107     if (!slice_buf_ids)
108         return -1;
109     vactx->slice_buf_ids = slice_buf_ids;
110
111     slice_param_buf_id = 0;
112     if (vaCreateBuffer(vactx->display, vactx->context_id,
113                        VASliceParameterBufferType,
114                        vactx->slice_param_size,
115                        vactx->slice_count, vactx->slice_params,
116                        &slice_param_buf_id) != VA_STATUS_SUCCESS)
117         return -1;
118     vactx->slice_count = 0;
119
120     slice_data_buf_id = 0;
121     if (vaCreateBuffer(vactx->display, vactx->context_id,
122                        VASliceDataBufferType,
123                        vactx->slice_data_size,
124                        1, (void *)vactx->slice_data,
125                        &slice_data_buf_id) != VA_STATUS_SUCCESS)
126         return -1;
127     vactx->slice_data = NULL;
128     vactx->slice_data_size = 0;
129
130     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_param_buf_id;
131     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_data_buf_id;
132     return 0;
133 }
134
135 VASliceParameterBufferBase *ff_vaapi_alloc_slice(struct vaapi_context *vactx, const uint8_t *buffer, uint32_t size)
136 {
137     uint8_t *slice_params;
138     VASliceParameterBufferBase *slice_param;
139
140     if (!vactx->slice_data)
141         vactx->slice_data = buffer;
142     if (vactx->slice_data + vactx->slice_data_size != buffer) {
143         if (commit_slices(vactx) < 0)
144             return NULL;
145         vactx->slice_data = buffer;
146     }
147
148     slice_params =
149         av_fast_realloc(vactx->slice_params,
150                         &vactx->slice_params_alloc,
151                         (vactx->slice_count + 1) * vactx->slice_param_size);
152     if (!slice_params)
153         return NULL;
154     vactx->slice_params = slice_params;
155
156     slice_param = (VASliceParameterBufferBase *)(slice_params + vactx->slice_count * vactx->slice_param_size);
157     slice_param->slice_data_size   = size;
158     slice_param->slice_data_offset = vactx->slice_data_size;
159     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
160
161     vactx->slice_count++;
162     vactx->slice_data_size += size;
163     return slice_param;
164 }
165
166 int ff_vaapi_common_end_frame(MpegEncContext *s)
167 {
168     struct vaapi_context * const vactx = s->avctx->hwaccel_context;
169     int ret = -1;
170
171     dprintf(s->avctx, "ff_vaapi_common_end_frame()\n");
172
173     if (commit_slices(vactx) < 0)
174         goto done;
175     if (vactx->n_slice_buf_ids > 0) {
176         if (render_picture(vactx, ff_vaapi_get_surface(s->current_picture_ptr)) < 0)
177             goto done;
178         ff_draw_horiz_band(s, 0, s->avctx->height);
179     }
180     ret = 0;
181
182 done:
183     destroy_buffers(vactx->display, &vactx->pic_param_buf_id, 1);
184     destroy_buffers(vactx->display, &vactx->iq_matrix_buf_id, 1);
185     destroy_buffers(vactx->display, &vactx->bitplane_buf_id, 1);
186     destroy_buffers(vactx->display, vactx->slice_buf_ids, vactx->n_slice_buf_ids);
187     av_freep(&vactx->bitplane_buffer);
188     av_freep(&vactx->slice_buf_ids);
189     av_freep(&vactx->slice_params);
190     vactx->n_slice_buf_ids     = 0;
191     vactx->slice_buf_ids_alloc = 0;
192     vactx->slice_count         = 0;
193     vactx->slice_params_alloc  = 0;
194     return ret;
195 }
196
197 /* @} */