st/va: make the implementation thread safe v2
[mesa.git] / src / gallium / state_trackers / va / picture.c
1 /**************************************************************************
2 *
3 * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4 * Copyright 2014 Advanced Micro Devices, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include "pipe/p_video_codec.h"
30
31 #include "util/u_handle_table.h"
32 #include "util/u_video.h"
33
34 #include "vl/vl_vlc.h"
35 #include "vl/vl_winsys.h"
36
37 #include "va_private.h"
38
39 VAStatus
40 vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID render_target)
41 {
42 vlVaDriver *drv;
43 vlVaContext *context;
44 vlVaSurface *surf;
45
46 if (!ctx)
47 return VA_STATUS_ERROR_INVALID_CONTEXT;
48
49 drv = VL_VA_DRIVER(ctx);
50 if (!drv)
51 return VA_STATUS_ERROR_INVALID_CONTEXT;
52
53 pipe_mutex_lock(drv->mutex);
54 context = handle_table_get(drv->htab, context_id);
55 if (!context) {
56 pipe_mutex_unlock(drv->mutex);
57 return VA_STATUS_ERROR_INVALID_CONTEXT;
58 }
59
60 surf = handle_table_get(drv->htab, render_target);
61 pipe_mutex_unlock(drv->mutex);
62 if (!surf || !surf->buffer)
63 return VA_STATUS_ERROR_INVALID_SURFACE;
64
65 context->target = surf->buffer;
66
67 if (!context->decoder) {
68
69 /* VPP */
70 if (context->templat.profile == PIPE_VIDEO_PROFILE_UNKNOWN &&
71 ((context->target->buffer_format != PIPE_FORMAT_B8G8R8A8_UNORM &&
72 context->target->buffer_format != PIPE_FORMAT_R8G8B8A8_UNORM &&
73 context->target->buffer_format != PIPE_FORMAT_B8G8R8X8_UNORM &&
74 context->target->buffer_format != PIPE_FORMAT_R8G8B8X8_UNORM) ||
75 context->target->interlaced))
76 return VA_STATUS_ERROR_UNIMPLEMENTED;
77
78 return VA_STATUS_SUCCESS;
79 }
80
81 context->decoder->begin_frame(context->decoder, context->target, &context->desc.base);
82
83 return VA_STATUS_SUCCESS;
84 }
85
86 void
87 vlVaGetReferenceFrame(vlVaDriver *drv, VASurfaceID surface_id,
88 struct pipe_video_buffer **ref_frame)
89 {
90 vlVaSurface *surf = handle_table_get(drv->htab, surface_id);
91 if (surf)
92 *ref_frame = surf->buffer;
93 else
94 *ref_frame = NULL;
95 }
96
97 static VAStatus
98 handlePictureParameterBuffer(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
99 {
100 VAStatus vaStatus = VA_STATUS_SUCCESS;
101
102 switch (u_reduce_video_profile(context->templat.profile)) {
103 case PIPE_VIDEO_FORMAT_MPEG12:
104 vlVaHandlePictureParameterBufferMPEG12(drv, context, buf);
105 break;
106
107 case PIPE_VIDEO_FORMAT_MPEG4_AVC:
108 vlVaHandlePictureParameterBufferH264(drv, context, buf);
109 break;
110
111 case PIPE_VIDEO_FORMAT_VC1:
112 vlVaHandlePictureParameterBufferVC1(drv, context, buf);
113 break;
114
115 case PIPE_VIDEO_FORMAT_MPEG4:
116 vlVaHandlePictureParameterBufferMPEG4(drv, context, buf);
117 break;
118
119 case PIPE_VIDEO_FORMAT_HEVC:
120 vlVaHandlePictureParameterBufferHEVC(drv, context, buf);
121 break;
122
123 default:
124 break;
125 }
126
127 /* Create the decoder once max_references is known. */
128 if (!context->decoder) {
129 if (!context->target)
130 return VA_STATUS_ERROR_INVALID_CONTEXT;
131
132 if (context->templat.max_references == 0)
133 return VA_STATUS_ERROR_INVALID_BUFFER;
134
135 if (u_reduce_video_profile(context->templat.profile) ==
136 PIPE_VIDEO_FORMAT_MPEG4_AVC)
137 context->templat.level = u_get_h264_level(context->templat.width,
138 context->templat.height, &context->templat.max_references);
139
140 context->decoder = drv->pipe->create_video_codec(drv->pipe,
141 &context->templat);
142
143 if (!context->decoder)
144 return VA_STATUS_ERROR_ALLOCATION_FAILED;
145
146 context->decoder->begin_frame(context->decoder, context->target,
147 &context->desc.base);
148 }
149
150 return vaStatus;
151 }
152
153 static void
154 handleIQMatrixBuffer(vlVaContext *context, vlVaBuffer *buf)
155 {
156 switch (u_reduce_video_profile(context->templat.profile)) {
157 case PIPE_VIDEO_FORMAT_MPEG12:
158 vlVaHandleIQMatrixBufferMPEG12(context, buf);
159 break;
160
161 case PIPE_VIDEO_FORMAT_MPEG4_AVC:
162 vlVaHandleIQMatrixBufferH264(context, buf);
163 break;
164
165 case PIPE_VIDEO_FORMAT_MPEG4:
166 vlVaHandleIQMatrixBufferMPEG4(context, buf);
167 break;
168
169 case PIPE_VIDEO_FORMAT_HEVC:
170 vlVaHandleIQMatrixBufferHEVC(context, buf);
171 break;
172
173 default:
174 break;
175 }
176 }
177
178 static void
179 handleSliceParameterBuffer(vlVaContext *context, vlVaBuffer *buf)
180 {
181 switch (u_reduce_video_profile(context->templat.profile)) {
182 case PIPE_VIDEO_FORMAT_MPEG12:
183 vlVaHandleSliceParameterBufferMPEG12(context, buf);
184 break;
185
186 case PIPE_VIDEO_FORMAT_VC1:
187 vlVaHandleSliceParameterBufferVC1(context, buf);
188 break;
189
190 case PIPE_VIDEO_FORMAT_MPEG4_AVC:
191 vlVaHandleSliceParameterBufferH264(context, buf);
192 break;
193
194 case PIPE_VIDEO_FORMAT_MPEG4:
195 vlVaHandleSliceParameterBufferMPEG4(context, buf);
196 break;
197
198 case PIPE_VIDEO_FORMAT_HEVC:
199 vlVaHandleSliceParameterBufferHEVC(context, buf);
200 break;
201
202 default:
203 break;
204 }
205 }
206
207 static unsigned int
208 bufHasStartcode(vlVaBuffer *buf, unsigned int code, unsigned int bits)
209 {
210 struct vl_vlc vlc = {0};
211 int i;
212
213 /* search the first 64 bytes for a startcode */
214 vl_vlc_init(&vlc, 1, (const void * const*)&buf->data, &buf->size);
215 for (i = 0; i < 64 && vl_vlc_bits_left(&vlc) >= bits; ++i) {
216 if (vl_vlc_peekbits(&vlc, bits) == code)
217 return 1;
218 vl_vlc_eatbits(&vlc, 8);
219 vl_vlc_fillbits(&vlc);
220 }
221
222 return 0;
223 }
224
225 static void
226 handleVASliceDataBufferType(vlVaContext *context, vlVaBuffer *buf)
227 {
228 enum pipe_video_format format;
229 unsigned num_buffers = 0;
230 void * const *buffers[2];
231 unsigned sizes[2];
232 static const uint8_t start_code_h264[] = { 0x00, 0x00, 0x01 };
233 static const uint8_t start_code_h265[] = { 0x00, 0x00, 0x01 };
234 static const uint8_t start_code_vc1[] = { 0x00, 0x00, 0x01, 0x0d };
235
236 format = u_reduce_video_profile(context->templat.profile);
237 switch (format) {
238 case PIPE_VIDEO_FORMAT_MPEG4_AVC:
239 if (bufHasStartcode(buf, 0x000001, 24))
240 break;
241
242 buffers[num_buffers] = (void *const)&start_code_h264;
243 sizes[num_buffers++] = sizeof(start_code_h264);
244 break;
245 case PIPE_VIDEO_FORMAT_HEVC:
246 if (bufHasStartcode(buf, 0x000001, 24))
247 break;
248
249 buffers[num_buffers] = (void *const)&start_code_h265;
250 sizes[num_buffers++] = sizeof(start_code_h265);
251 break;
252 case PIPE_VIDEO_FORMAT_VC1:
253 if (bufHasStartcode(buf, 0x0000010d, 32) ||
254 bufHasStartcode(buf, 0x0000010c, 32) ||
255 bufHasStartcode(buf, 0x0000010b, 32))
256 break;
257
258 if (context->decoder->profile == PIPE_VIDEO_PROFILE_VC1_ADVANCED) {
259 buffers[num_buffers] = (void *const)&start_code_vc1;
260 sizes[num_buffers++] = sizeof(start_code_vc1);
261 }
262 break;
263 case PIPE_VIDEO_FORMAT_MPEG4:
264 if (bufHasStartcode(buf, 0x000001, 24))
265 break;
266
267 vlVaDecoderFixMPEG4Startcode(context);
268 buffers[num_buffers] = (void *)context->mpeg4.start_code;
269 sizes[num_buffers++] = context->mpeg4.start_code_size;
270 default:
271 break;
272 }
273
274 buffers[num_buffers] = buf->data;
275 sizes[num_buffers] = buf->size;
276 ++num_buffers;
277 context->decoder->decode_bitstream(context->decoder, context->target, &context->desc.base,
278 num_buffers, (const void * const*)buffers, sizes);
279 }
280
281 VAStatus
282 vlVaRenderPicture(VADriverContextP ctx, VAContextID context_id, VABufferID *buffers, int num_buffers)
283 {
284 vlVaDriver *drv;
285 vlVaContext *context;
286 VAStatus vaStatus = VA_STATUS_SUCCESS;
287
288 unsigned i;
289
290 if (!ctx)
291 return VA_STATUS_ERROR_INVALID_CONTEXT;
292
293 drv = VL_VA_DRIVER(ctx);
294 if (!drv)
295 return VA_STATUS_ERROR_INVALID_CONTEXT;
296
297 pipe_mutex_lock(drv->mutex);
298 context = handle_table_get(drv->htab, context_id);
299 if (!context) {
300 pipe_mutex_unlock(drv->mutex);
301 return VA_STATUS_ERROR_INVALID_CONTEXT;
302 }
303
304 for (i = 0; i < num_buffers; ++i) {
305 vlVaBuffer *buf = handle_table_get(drv->htab, buffers[i]);
306 if (!buf) {
307 pipe_mutex_unlock(drv->mutex);
308 return VA_STATUS_ERROR_INVALID_BUFFER;
309 }
310
311 switch (buf->type) {
312 case VAPictureParameterBufferType:
313 vaStatus = handlePictureParameterBuffer(drv, context, buf);
314 break;
315
316 case VAIQMatrixBufferType:
317 handleIQMatrixBuffer(context, buf);
318 break;
319
320 case VASliceParameterBufferType:
321 handleSliceParameterBuffer(context, buf);
322 break;
323
324 case VASliceDataBufferType:
325 handleVASliceDataBufferType(context, buf);
326 break;
327 case VAProcPipelineParameterBufferType:
328 vaStatus = vlVaHandleVAProcPipelineParameterBufferType(drv, context, buf);
329 break;
330
331 default:
332 break;
333 }
334 }
335 pipe_mutex_unlock(drv->mutex);
336
337 return vaStatus;
338 }
339
340 VAStatus
341 vlVaEndPicture(VADriverContextP ctx, VAContextID context_id)
342 {
343 vlVaDriver *drv;
344 vlVaContext *context;
345
346 if (!ctx)
347 return VA_STATUS_ERROR_INVALID_CONTEXT;
348
349 drv = VL_VA_DRIVER(ctx);
350 if (!drv)
351 return VA_STATUS_ERROR_INVALID_CONTEXT;
352
353 pipe_mutex_lock(drv->mutex);
354 context = handle_table_get(drv->htab, context_id);
355 pipe_mutex_unlock(drv->mutex);
356 if (!context)
357 return VA_STATUS_ERROR_INVALID_CONTEXT;
358
359 if (!context->decoder) {
360 if (context->templat.profile != PIPE_VIDEO_PROFILE_UNKNOWN)
361 return VA_STATUS_ERROR_INVALID_CONTEXT;
362
363 /* VPP */
364 return VA_STATUS_SUCCESS;
365 }
366
367 context->mpeg4.frame_num++;
368 context->decoder->end_frame(context->decoder, context->target, &context->desc.base);
369
370 return VA_STATUS_SUCCESS;
371 }