• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_screen.h"
30 #include "frontend/drm_driver.h"
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_transfer.h"
34 #include "util/set.h"
35 #include "vl/vl_winsys.h"
36 
37 #include "va_private.h"
38 
39 #ifdef _WIN32
40 #include <va/va_win32.h>
41 #endif
42 
43 #ifndef VA_MAPBUFFER_FLAG_DEFAULT
44 #define VA_MAPBUFFER_FLAG_DEFAULT 0
45 #define VA_MAPBUFFER_FLAG_READ    1
46 #define VA_MAPBUFFER_FLAG_WRITE   2
47 #endif
48 
49 VAStatus
vlVaCreateBuffer(VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void * data,VABufferID * buf_id)50 vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type,
51                  unsigned int size, unsigned int num_elements, void *data,
52                  VABufferID *buf_id)
53 {
54    vlVaDriver *drv;
55    vlVaBuffer *buf;
56 
57    if (!ctx)
58       return VA_STATUS_ERROR_INVALID_CONTEXT;
59 
60    buf = CALLOC(1, sizeof(vlVaBuffer));
61    if (!buf)
62       return VA_STATUS_ERROR_ALLOCATION_FAILED;
63 
64    buf->type = type;
65    buf->size = size;
66    buf->num_elements = num_elements;
67 
68    if (buf->type == VAEncCodedBufferType)
69       buf->data = CALLOC(1, sizeof(VACodedBufferSegment));
70    else
71       buf->data = MALLOC(size * num_elements);
72 
73    if (!buf->data) {
74       FREE(buf);
75       return VA_STATUS_ERROR_ALLOCATION_FAILED;
76    }
77 
78    if (data)
79       memcpy(buf->data, data, size * num_elements);
80 
81    drv = VL_VA_DRIVER(ctx);
82    mtx_lock(&drv->mutex);
83    *buf_id = handle_table_add(drv->htab, buf);
84    mtx_unlock(&drv->mutex);
85 
86    return VA_STATUS_SUCCESS;
87 }
88 
89 VAStatus
vlVaBufferSetNumElements(VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements)90 vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id,
91                          unsigned int num_elements)
92 {
93    vlVaDriver *drv;
94    vlVaBuffer *buf;
95 
96    if (!ctx)
97       return VA_STATUS_ERROR_INVALID_CONTEXT;
98 
99    drv = VL_VA_DRIVER(ctx);
100    mtx_lock(&drv->mutex);
101    buf = handle_table_get(drv->htab, buf_id);
102    mtx_unlock(&drv->mutex);
103    if (!buf)
104       return VA_STATUS_ERROR_INVALID_BUFFER;
105 
106    if (buf->derived_surface.resource)
107       return VA_STATUS_ERROR_INVALID_BUFFER;
108 
109    buf->data = REALLOC(buf->data, buf->size * buf->num_elements,
110                        buf->size * num_elements);
111    buf->num_elements = num_elements;
112 
113    if (!buf->data)
114       return VA_STATUS_ERROR_ALLOCATION_FAILED;
115 
116    return VA_STATUS_SUCCESS;
117 }
118 
119 VAStatus
vlVaMapBuffer(VADriverContextP ctx,VABufferID buf_id,void ** pbuff)120 vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
121 {
122    return vlVaMapBuffer2(ctx, buf_id, pbuff, VA_MAPBUFFER_FLAG_DEFAULT);
123 }
124 
vlVaMapBuffer2(VADriverContextP ctx,VABufferID buf_id,void ** pbuff,uint32_t flags)125 VAStatus vlVaMapBuffer2(VADriverContextP ctx, VABufferID buf_id,
126                         void **pbuff, uint32_t flags)
127 {
128    vlVaDriver *drv;
129    vlVaBuffer *buf;
130 
131    if (!ctx)
132       return VA_STATUS_ERROR_INVALID_CONTEXT;
133 
134    drv = VL_VA_DRIVER(ctx);
135    if (!drv)
136       return VA_STATUS_ERROR_INVALID_CONTEXT;
137 
138    if (!pbuff)
139       return VA_STATUS_ERROR_INVALID_PARAMETER;
140 
141    mtx_lock(&drv->mutex);
142    buf = handle_table_get(drv->htab, buf_id);
143    if (!buf || buf->export_refcount > 0) {
144       mtx_unlock(&drv->mutex);
145       return VA_STATUS_ERROR_INVALID_BUFFER;
146    }
147 
148    if (buf->type == VAEncCodedBufferType)
149       vlVaGetBufferFeedback(buf);
150 
151    if (buf->derived_surface.resource) {
152       struct pipe_resource *resource;
153       struct pipe_box box;
154       unsigned usage = 0;
155       void *(*map_func)(struct pipe_context *,
156              struct pipe_resource *resource,
157              unsigned level,
158              unsigned usage,  /* a combination of PIPE_MAP_x */
159              const struct pipe_box *,
160              struct pipe_transfer **out_transfer);
161 
162       memset(&box, 0, sizeof(box));
163       resource = buf->derived_surface.resource;
164       box.width = resource->width0;
165       box.height = resource->height0;
166       box.depth = resource->depth0;
167 
168       if (resource->target == PIPE_BUFFER)
169          map_func = drv->pipe->buffer_map;
170       else
171          map_func = drv->pipe->texture_map;
172 
173       if (flags == VA_MAPBUFFER_FLAG_DEFAULT) {
174          /* For VAImageBufferType, use PIPE_MAP_WRITE for now,
175           * PIPE_MAP_READ_WRITE degradate perf with two copies when map/unmap. */
176          if (buf->type == VAEncCodedBufferType)
177             usage = PIPE_MAP_READ;
178          else
179             usage = PIPE_MAP_WRITE;
180 
181          /* Map decoder and postproc surfaces also for reading. */
182          if (buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM ||
183              buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING)
184             usage |= PIPE_MAP_READ;
185       }
186 
187       if (flags & VA_MAPBUFFER_FLAG_READ)
188          usage |= PIPE_MAP_READ;
189       if (flags & VA_MAPBUFFER_FLAG_WRITE)
190          usage |= PIPE_MAP_WRITE;
191 
192       assert(usage);
193 
194       *pbuff = map_func(drv->pipe, resource, 0, usage,
195                         &box, &buf->derived_surface.transfer);
196       mtx_unlock(&drv->mutex);
197 
198       if (!buf->derived_surface.transfer || !*pbuff)
199          return VA_STATUS_ERROR_INVALID_BUFFER;
200 
201       if (buf->type == VAEncCodedBufferType) {
202          VACodedBufferSegment* curr_buf_ptr = (VACodedBufferSegment*) buf->data;
203 
204          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_ENCODE_RESULT) &&
205              (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED)) {
206             curr_buf_ptr->status = VA_CODED_BUF_STATUS_BAD_BITSTREAM;
207             return VA_STATUS_ERROR_OPERATION_FAILED;
208          }
209 
210          curr_buf_ptr->status = (buf->extended_metadata.average_frame_qp & VA_CODED_BUF_STATUS_PICTURE_AVE_QP_MASK);
211          if (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_MAX_FRAME_SIZE_OVERFLOW)
212             curr_buf_ptr->status |= VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW;
213 
214          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_CODEC_UNIT_LOCATION) == 0) {
215             curr_buf_ptr->buf = *pbuff;
216             curr_buf_ptr->size = buf->coded_size;
217             *pbuff = buf->data;
218          } else {
219             uint8_t* compressed_bitstream_data = *pbuff;
220             *pbuff = buf->data;
221 
222             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count - 1; i++) {
223                if (!curr_buf_ptr->next)
224                   curr_buf_ptr->next = CALLOC(1, sizeof(VACodedBufferSegment));
225                if (!curr_buf_ptr->next)
226                   return VA_STATUS_ERROR_ALLOCATION_FAILED;
227                curr_buf_ptr = curr_buf_ptr->next;
228             }
229             if (curr_buf_ptr->next) {
230                VACodedBufferSegment *node = curr_buf_ptr->next;
231                while (node) {
232                   VACodedBufferSegment *next = node->next;
233                   FREE(node);
234                   node = next;
235                }
236             }
237             curr_buf_ptr->next = NULL;
238 
239             curr_buf_ptr = buf->data;
240             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count; i++) {
241                curr_buf_ptr->size = buf->extended_metadata.codec_unit_metadata[i].size;
242                curr_buf_ptr->buf = compressed_bitstream_data + buf->extended_metadata.codec_unit_metadata[i].offset;
243                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_MAX_SLICE_SIZE_OVERFLOW)
244                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
245                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_SINGLE_NALU)
246                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SINGLE_NALU;
247 
248                curr_buf_ptr = curr_buf_ptr->next;
249             }
250          }
251       }
252    } else {
253       mtx_unlock(&drv->mutex);
254       *pbuff = buf->data;
255    }
256 
257    return VA_STATUS_SUCCESS;
258 }
259 
260 VAStatus
vlVaUnmapBuffer(VADriverContextP ctx,VABufferID buf_id)261 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
262 {
263    vlVaDriver *drv;
264    vlVaBuffer *buf;
265    struct pipe_resource *resource;
266 
267    if (!ctx)
268       return VA_STATUS_ERROR_INVALID_CONTEXT;
269 
270    drv = VL_VA_DRIVER(ctx);
271    if (!drv)
272       return VA_STATUS_ERROR_INVALID_CONTEXT;
273 
274    mtx_lock(&drv->mutex);
275    buf = handle_table_get(drv->htab, buf_id);
276    if (!buf || buf->export_refcount > 0) {
277       mtx_unlock(&drv->mutex);
278       return VA_STATUS_ERROR_INVALID_BUFFER;
279    }
280 
281    resource = buf->derived_surface.resource;
282    if (resource) {
283       void (*unmap_func)(struct pipe_context *pipe,
284                          struct pipe_transfer *transfer);
285 
286       if (!buf->derived_surface.transfer) {
287          mtx_unlock(&drv->mutex);
288          return VA_STATUS_ERROR_INVALID_BUFFER;
289       }
290 
291       if (resource->target == PIPE_BUFFER)
292          unmap_func = pipe_buffer_unmap;
293       else
294          unmap_func = pipe_texture_unmap;
295 
296       unmap_func(drv->pipe, buf->derived_surface.transfer);
297       buf->derived_surface.transfer = NULL;
298 
299       if (buf->type == VAImageBufferType)
300          drv->pipe->flush(drv->pipe, NULL, 0);
301    }
302    mtx_unlock(&drv->mutex);
303 
304    return VA_STATUS_SUCCESS;
305 }
306 
307 VAStatus
vlVaDestroyBuffer(VADriverContextP ctx,VABufferID buf_id)308 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
309 {
310    vlVaDriver *drv;
311    vlVaBuffer *buf;
312 
313    if (!ctx)
314       return VA_STATUS_ERROR_INVALID_CONTEXT;
315 
316    drv = VL_VA_DRIVER(ctx);
317    mtx_lock(&drv->mutex);
318    buf = handle_table_get(drv->htab, buf_id);
319    if (!buf) {
320       mtx_unlock(&drv->mutex);
321       return VA_STATUS_ERROR_INVALID_BUFFER;
322    }
323 
324    if (buf->derived_surface.resource)
325       pipe_resource_reference(&buf->derived_surface.resource, NULL);
326 
327    if (buf->type == VAEncCodedBufferType) {
328       VACodedBufferSegment* node = buf->data;
329       while (node) {
330          VACodedBufferSegment* next = (VACodedBufferSegment*) node->next;
331          FREE(node);
332          node = next;
333       }
334    } else {
335       FREE(buf->data);
336    }
337 
338    if (buf->ctx) {
339       assert(_mesa_set_search(buf->ctx->buffers, buf));
340       _mesa_set_remove_key(buf->ctx->buffers, buf);
341       vlVaGetBufferFeedback(buf);
342       if (buf->fence && buf->ctx->decoder && buf->ctx->decoder->destroy_fence)
343          buf->ctx->decoder->destroy_fence(buf->ctx->decoder, buf->fence);
344    }
345 
346    if (buf->coded_surf)
347       buf->coded_surf->coded_buf = NULL;
348 
349    FREE(buf);
350    handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id);
351    mtx_unlock(&drv->mutex);
352 
353    return VA_STATUS_SUCCESS;
354 }
355 
356 VAStatus
vlVaBufferInfo(VADriverContextP ctx,VABufferID buf_id,VABufferType * type,unsigned int * size,unsigned int * num_elements)357 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type,
358                unsigned int *size, unsigned int *num_elements)
359 {
360    vlVaDriver *drv;
361    vlVaBuffer *buf;
362 
363    if (!ctx)
364       return VA_STATUS_ERROR_INVALID_CONTEXT;
365 
366    drv = VL_VA_DRIVER(ctx);
367    mtx_lock(&drv->mutex);
368    buf = handle_table_get(drv->htab, buf_id);
369    mtx_unlock(&drv->mutex);
370    if (!buf)
371       return VA_STATUS_ERROR_INVALID_BUFFER;
372 
373    *type = buf->type;
374    *size = buf->size;
375    *num_elements = buf->num_elements;
376 
377    return VA_STATUS_SUCCESS;
378 }
379 
380 VAStatus
vlVaAcquireBufferHandle(VADriverContextP ctx,VABufferID buf_id,VABufferInfo * out_buf_info)381 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
382                         VABufferInfo *out_buf_info)
383 {
384    vlVaDriver *drv;
385    uint32_t i;
386    uint32_t mem_type;
387    vlVaBuffer *buf ;
388    struct pipe_screen *screen;
389 
390    /* List of supported memory types, in preferred order. */
391    static const uint32_t mem_types[] = {
392 #ifdef _WIN32
393       VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE,
394       VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE,
395 #else
396       VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
397 #endif
398       0
399    };
400 
401    if (!ctx)
402       return VA_STATUS_ERROR_INVALID_CONTEXT;
403 
404    drv = VL_VA_DRIVER(ctx);
405    screen = VL_VA_PSCREEN(ctx);
406    mtx_lock(&drv->mutex);
407    buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
408    mtx_unlock(&drv->mutex);
409 
410    if (!buf)
411       return VA_STATUS_ERROR_INVALID_BUFFER;
412 
413    /* Only VA surface|image like buffers are supported for now .*/
414    if (buf->type != VAImageBufferType)
415       return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
416 
417    if (!out_buf_info)
418       return VA_STATUS_ERROR_INVALID_PARAMETER;
419 
420    if (!out_buf_info->mem_type)
421       mem_type = mem_types[0];
422    else {
423       mem_type = 0;
424       for (i = 0; mem_types[i] != 0; i++) {
425          if (out_buf_info->mem_type & mem_types[i]) {
426             mem_type = out_buf_info->mem_type;
427             break;
428          }
429       }
430       if (!mem_type)
431          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
432    }
433 
434    if (!buf->derived_surface.resource)
435       return VA_STATUS_ERROR_INVALID_BUFFER;
436 
437    if (buf->export_refcount > 0) {
438       if (buf->export_state.mem_type != mem_type)
439          return VA_STATUS_ERROR_INVALID_PARAMETER;
440    } else {
441       VABufferInfo * const buf_info = &buf->export_state;
442 
443       switch (mem_type) {
444 #ifdef _WIN32
445       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
446       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
447 #else
448       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
449 #endif
450       {
451          struct winsys_handle whandle;
452 
453          mtx_lock(&drv->mutex);
454 
455          memset(&whandle, 0, sizeof(whandle));
456          whandle.type = WINSYS_HANDLE_TYPE_FD;
457 
458 #ifdef _WIN32
459          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
460             whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
461 #endif
462          if (!screen->resource_get_handle(screen, drv->pipe,
463                                           buf->derived_surface.resource,
464                                           &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) {
465             mtx_unlock(&drv->mutex);
466             return VA_STATUS_ERROR_INVALID_BUFFER;
467          }
468 
469          mtx_unlock(&drv->mutex);
470 
471          buf_info->handle = (intptr_t)whandle.handle;
472 
473 #ifdef _WIN32
474          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
475             buf_info->handle = (intptr_t)whandle.com_obj;
476 #endif
477          break;
478       }
479       default:
480          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
481       }
482 
483       buf_info->type = buf->type;
484       buf_info->mem_type = mem_type;
485       buf_info->mem_size = buf->num_elements * buf->size;
486    }
487 
488    buf->export_refcount++;
489 
490    *out_buf_info = buf->export_state;
491 
492    return VA_STATUS_SUCCESS;
493 }
494 
495 VAStatus
vlVaReleaseBufferHandle(VADriverContextP ctx,VABufferID buf_id)496 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
497 {
498    vlVaDriver *drv;
499    vlVaBuffer *buf;
500 
501    if (!ctx)
502       return VA_STATUS_ERROR_INVALID_CONTEXT;
503 
504    drv = VL_VA_DRIVER(ctx);
505    mtx_lock(&drv->mutex);
506    buf = handle_table_get(drv->htab, buf_id);
507    mtx_unlock(&drv->mutex);
508 
509    if (!buf)
510       return VA_STATUS_ERROR_INVALID_BUFFER;
511 
512    if (buf->export_refcount == 0)
513       return VA_STATUS_ERROR_INVALID_BUFFER;
514 
515    if (--buf->export_refcount == 0) {
516       VABufferInfo * const buf_info = &buf->export_state;
517 
518       switch (buf_info->mem_type) {
519 #ifdef _WIN32
520       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
521          // Do nothing for this case.
522          break;
523       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
524          CloseHandle((HANDLE) buf_info->handle);
525       break;
526 #else
527       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
528          close((intptr_t)buf_info->handle);
529          break;
530 #endif
531       default:
532          return VA_STATUS_ERROR_INVALID_BUFFER;
533       }
534 
535       buf_info->mem_type = 0;
536    }
537 
538    return VA_STATUS_SUCCESS;
539 }
540 
541 #if VA_CHECK_VERSION(1, 15, 0)
542 VAStatus
vlVaSyncBuffer(VADriverContextP ctx,VABufferID buf_id,uint64_t timeout_ns)543 vlVaSyncBuffer(VADriverContextP ctx, VABufferID buf_id, uint64_t timeout_ns)
544 {
545    vlVaDriver *drv;
546    vlVaContext *context;
547    vlVaBuffer *buf;
548 
549    if (!ctx)
550       return VA_STATUS_ERROR_INVALID_CONTEXT;
551 
552    drv = VL_VA_DRIVER(ctx);
553    if (!drv)
554       return VA_STATUS_ERROR_INVALID_CONTEXT;
555 
556    mtx_lock(&drv->mutex);
557    buf = handle_table_get(drv->htab, buf_id);
558    if (!buf) {
559       mtx_unlock(&drv->mutex);
560       return VA_STATUS_ERROR_INVALID_BUFFER;
561    }
562 
563    /* No outstanding operation: nothing to do. */
564    if (!buf->fence) {
565       mtx_unlock(&drv->mutex);
566       return VA_STATUS_SUCCESS;
567    }
568 
569    context = buf->ctx;
570    if (!context || !context->decoder) {
571       mtx_unlock(&drv->mutex);
572       return VA_STATUS_ERROR_INVALID_CONTEXT;
573    }
574 
575    mtx_lock(&context->mutex);
576    mtx_unlock(&drv->mutex);
577    int ret = context->decoder->fence_wait(context->decoder, buf->fence, timeout_ns);
578    mtx_unlock(&context->mutex);
579    return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT;
580 }
581 #endif
582 
vlVaGetBufferFeedback(vlVaBuffer * buf)583 void vlVaGetBufferFeedback(vlVaBuffer *buf)
584 {
585    if (!buf->ctx || !buf->ctx->decoder || !buf->feedback)
586       return;
587 
588    buf->ctx->decoder->get_feedback(buf->ctx->decoder, buf->feedback,
589                                    &buf->coded_size, &buf->extended_metadata);
590    buf->feedback = NULL;
591 }
592