FFmpeg  4.3.7
amfenc.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "config.h"
20 
21 #include "libavutil/avassert.h"
22 #include "libavutil/imgutils.h"
23 #include "libavutil/hwcontext.h"
24 #if CONFIG_D3D11VA
26 #endif
27 #if CONFIG_DXVA2
28 #define COBJMACROS
30 #endif
31 #include "libavutil/mem.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/time.h"
34 
35 #include "amfenc.h"
36 #include "internal.h"
37 
38 #if CONFIG_D3D11VA
39 #include <d3d11.h>
40 #endif
41 
42 #ifdef _WIN32
43 #include "compat/w32dlfcn.h"
44 #else
45 #include <dlfcn.h>
46 #endif
47 
48 #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
49 
50 #define PTS_PROP L"PtsProp"
51 
55 #if CONFIG_D3D11VA
57 #endif
58 #if CONFIG_DXVA2
60 #endif
62 };
63 
64 typedef struct FormatMap {
66  enum AMF_SURFACE_FORMAT amf_format;
67 } FormatMap;
68 
69 static const FormatMap format_map[] =
70 {
71  { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
72  { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
73  { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
74  { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
75  { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
76  { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
77  { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
78 };
79 
80 static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
81 {
82  int i;
83  for (i = 0; i < amf_countof(format_map); i++) {
84  if (format_map[i].av_format == fmt) {
85  return format_map[i].amf_format;
86  }
87  }
88  return AMF_SURFACE_UNKNOWN;
89 }
90 
91 static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
92  const wchar_t *scope, const wchar_t *message)
93 {
94  AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
95  av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
96 }
97 
98 static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
99 {
100 }
101 
102 static AMFTraceWriterVtbl tracer_vtbl =
103 {
104  .Write = AMFTraceWriter_Write,
105  .Flush = AMFTraceWriter_Flush,
106 };
107 
109 {
110  AmfContext *ctx = avctx->priv_data;
111  AMFInit_Fn init_fun;
112  AMFQueryVersion_Fn version_fun;
113  AMF_RESULT res;
114 
115  ctx->delayed_frame = av_frame_alloc();
116  if (!ctx->delayed_frame) {
117  return AVERROR(ENOMEM);
118  }
119  // hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small
120  ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t));
121  if (!ctx->timestamp_list) {
122  return AVERROR(ENOMEM);
123  }
124  ctx->dts_delay = 0;
125 
126 
127  ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
128  AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL,
129  AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
130 
131  init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME);
132  AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME);
133 
134  version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
135  AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
136 
137  res = version_fun(&ctx->version);
138  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
139  res = init_fun(AMF_FULL_VERSION, &ctx->factory);
140  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
141  res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace);
142  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
143  res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug);
144  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
145  return 0;
146 }
147 
148 #if CONFIG_D3D11VA
149 static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx)
150 {
151  AmfContext *ctx = avctx->priv_data;
152  AMF_RESULT res;
153 
154  res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1);
155  if (res != AMF_OK) {
156  if (res == AMF_NOT_SUPPORTED)
157  av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
158  else
159  av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
160  return AVERROR(ENODEV);
161  }
162 
163  return 0;
164 }
165 #endif
166 
167 #if CONFIG_DXVA2
168 static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx)
169 {
170  AmfContext *ctx = avctx->priv_data;
171  HANDLE device_handle;
172  IDirect3DDevice9 *device;
173  HRESULT hr;
174  AMF_RESULT res;
175  int ret;
176 
177  hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
178  if (FAILED(hr)) {
179  av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
180  return AVERROR_EXTERNAL;
181  }
182 
183  hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
184  if (SUCCEEDED(hr)) {
185  IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
186  ret = 0;
187  } else {
188  av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
189  ret = AVERROR_EXTERNAL;
190  }
191 
192  IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
193 
194  if (ret < 0)
195  return ret;
196 
197  res = ctx->context->pVtbl->InitDX9(ctx->context, device);
198 
199  IDirect3DDevice9_Release(device);
200 
201  if (res != AMF_OK) {
202  if (res == AMF_NOT_SUPPORTED)
203  av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
204  else
205  av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
206  return AVERROR(ENODEV);
207  }
208 
209  return 0;
210 }
211 #endif
212 
214 {
215  AmfContext *ctx = avctx->priv_data;
216  AMFContext1 *context1 = NULL;
217  AMF_RESULT res;
218  av_unused int ret;
219 
220  ctx->hwsurfaces_in_queue = 0;
221  ctx->hwsurfaces_in_queue_max = 16;
222 
223  // configure AMF logger
224  // the return of these functions indicates old state and do not affect behaviour
225  ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 );
226  if (ctx->log_to_dbg)
227  ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE);
228  ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0);
229  ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE);
230 
231  // connect AMF logger to av_log
232  ctx->tracer.vtbl = &tracer_vtbl;
233  ctx->tracer.avctx = avctx;
234  ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1);
235  ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
236 
237  res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
238  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
239 
240  // If a device was passed to the encoder, try to initialise from that.
241  if (avctx->hw_frames_ctx) {
242  AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
243 
244  if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) {
245  av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n",
246  av_get_pix_fmt_name(frames_ctx->sw_format));
247  return AVERROR(EINVAL);
248  }
249 
250  switch (frames_ctx->device_ctx->type) {
251 #if CONFIG_D3D11VA
253  ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx);
254  if (ret < 0)
255  return ret;
256  break;
257 #endif
258 #if CONFIG_DXVA2
260  ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx);
261  if (ret < 0)
262  return ret;
263  break;
264 #endif
265  default:
266  av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n",
268  return AVERROR(ENOSYS);
269  }
270 
272  if (!ctx->hw_frames_ctx)
273  return AVERROR(ENOMEM);
274 
275  if (frames_ctx->initial_pool_size > 0)
276  ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1;
277 
278  } else if (avctx->hw_device_ctx) {
279  AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data;
280 
281  switch (device_ctx->type) {
282 #if CONFIG_D3D11VA
284  ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx);
285  if (ret < 0)
286  return ret;
287  break;
288 #endif
289 #if CONFIG_DXVA2
291  ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx);
292  if (ret < 0)
293  return ret;
294  break;
295 #endif
296  default:
297  av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
298  av_hwdevice_get_type_name(device_ctx->type));
299  return AVERROR(ENOSYS);
300  }
301 
303  if (!ctx->hw_device_ctx)
304  return AVERROR(ENOMEM);
305 
306  } else {
307  res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
308  if (res == AMF_OK) {
309  av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
310  } else {
311  res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
312  if (res == AMF_OK) {
313  av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
314  } else {
315  AMFGuid guid = IID_AMFContext1();
316  res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1);
317  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
318 
319  res = context1->pVtbl->InitVulkan(context1, NULL);
320  context1->pVtbl->Release(context1);
321  if (res != AMF_OK) {
322  if (res == AMF_NOT_SUPPORTED)
323  av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
324  else
325  av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
326  return AVERROR(ENOSYS);
327  }
328  av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
329  }
330  }
331  }
332  return 0;
333 }
334 
336 {
337  AmfContext *ctx = avctx->priv_data;
338  const wchar_t *codec_id = NULL;
339  AMF_RESULT res;
340  enum AVPixelFormat pix_fmt;
341 
342  switch (avctx->codec->id) {
343  case AV_CODEC_ID_H264:
344  codec_id = AMFVideoEncoderVCE_AVC;
345  break;
346  case AV_CODEC_ID_HEVC:
347  codec_id = AMFVideoEncoder_HEVC;
348  break;
349  default:
350  break;
351  }
352  AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id);
353 
354  if (ctx->hw_frames_ctx)
355  pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format;
356  else
357  pix_fmt = avctx->pix_fmt;
358 
359  ctx->format = amf_av_to_amf_format(pix_fmt);
360  AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL),
361  "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt));
362 
363  res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder);
364  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res);
365 
366  return 0;
367 }
368 
370 {
371  AmfContext *ctx = avctx->priv_data;
372 
373  if (ctx->delayed_surface) {
374  ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
375  ctx->delayed_surface = NULL;
376  }
377 
378  if (ctx->encoder) {
379  ctx->encoder->pVtbl->Terminate(ctx->encoder);
380  ctx->encoder->pVtbl->Release(ctx->encoder);
381  ctx->encoder = NULL;
382  }
383 
384  if (ctx->context) {
385  ctx->context->pVtbl->Terminate(ctx->context);
386  ctx->context->pVtbl->Release(ctx->context);
387  ctx->context = NULL;
388  }
391 
392  if (ctx->trace) {
393  ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID);
394  }
395  if (ctx->library) {
396  dlclose(ctx->library);
397  ctx->library = NULL;
398  }
399  ctx->trace = NULL;
400  ctx->debug = NULL;
401  ctx->factory = NULL;
402  ctx->version = 0;
403  ctx->delayed_drain = 0;
406 
407  return 0;
408 }
409 
410 static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
411  AMFSurface* surface)
412 {
413  AMFPlane *plane;
414  uint8_t *dst_data[4];
415  int dst_linesize[4];
416  int planes;
417  int i;
418 
419  planes = surface->pVtbl->GetPlanesCount(surface);
420  av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
421 
422  for (i = 0; i < planes; i++) {
423  plane = surface->pVtbl->GetPlaneAt(surface, i);
424  dst_data[i] = plane->pVtbl->GetNative(plane);
425  dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
426  }
427  av_image_copy(dst_data, dst_linesize,
428  (const uint8_t**)frame->data, frame->linesize, frame->format,
429  avctx->width, avctx->height);
430 
431  return 0;
432 }
433 
434 static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp)
435 {
436  AmfContext *ctx = avctx->priv_data;
437  if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) {
438  if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) {
439  return AVERROR(ENOMEM);
440  }
441  }
442  av_fifo_generic_write(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
443  return 0;
444 }
445 
446 static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
447 {
448  AmfContext *ctx = avctx->priv_data;
449  int ret;
450  AMFVariantStruct var = {0};
451  int64_t timestamp = AV_NOPTS_VALUE;
452  int64_t size = buffer->pVtbl->GetSize(buffer);
453 
454  if ((ret = av_new_packet(pkt, size)) < 0) {
455  return ret;
456  }
457  memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size);
458 
459  switch (avctx->codec->id) {
460  case AV_CODEC_ID_H264:
461  buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var);
462  if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
463  pkt->flags = AV_PKT_FLAG_KEY;
464  }
465  break;
466  case AV_CODEC_ID_HEVC:
467  buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var);
468  if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) {
469  pkt->flags = AV_PKT_FLAG_KEY;
470  }
471  break;
472  default:
473  break;
474  }
475 
476  buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var);
477 
478  pkt->pts = var.int64Value; // original pts
479 
480 
481  AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty\n");
482 
483  av_fifo_generic_read(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
484 
485  // calc dts shift if max_b_frames > 0
486  if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) {
487  int64_t timestamp_last = AV_NOPTS_VALUE;
489  "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames);
491  ctx->timestamp_list,
492  &timestamp_last,
493  (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last),
494  sizeof(timestamp_last),
495  NULL);
496  if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) {
497  return AVERROR(ERANGE);
498  }
499  ctx->dts_delay = timestamp_last - timestamp;
500  }
501  pkt->dts = timestamp - ctx->dts_delay;
502  return 0;
503 }
504 
505 // amfenc API implementation
507 {
508  int ret;
509 
510  if ((ret = amf_load_library(avctx)) == 0) {
511  if ((ret = amf_init_context(avctx)) == 0) {
512  if ((ret = amf_init_encoder(avctx)) == 0) {
513  return 0;
514  }
515  }
516  }
517  ff_amf_encode_close(avctx);
518  return ret;
519 }
520 
521 static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val)
522 {
523  AMF_RESULT res;
524  AMFVariantStruct var;
525  res = AMFVariantInit(&var);
526  if (res == AMF_OK) {
527  AMFGuid guid_AMFInterface = IID_AMFInterface();
528  AMFInterface *amf_interface;
529  res = val->pVtbl->QueryInterface(val, &guid_AMFInterface, (void**)&amf_interface);
530 
531  if (res == AMF_OK) {
532  res = AMFVariantAssignInterface(&var, amf_interface);
533  amf_interface->pVtbl->Release(amf_interface);
534  }
535  if (res == AMF_OK) {
536  res = object->pVtbl->SetProperty(object, name, var);
537  }
538  AMFVariantClear(&var);
539  }
540  return res;
541 }
542 
543 static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val)
544 {
545  AMF_RESULT res;
546  AMFVariantStruct var;
547  res = AMFVariantInit(&var);
548  if (res == AMF_OK) {
549  res = object->pVtbl->GetProperty(object, name, &var);
550  if (res == AMF_OK) {
551  if (var.type == AMF_VARIANT_INTERFACE) {
552  AMFGuid guid_AMFBuffer = IID_AMFBuffer();
553  AMFInterface *amf_interface = AMFVariantInterface(&var);
554  res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val);
555  } else {
556  res = AMF_INVALID_DATA_TYPE;
557  }
558  }
559  AMFVariantClear(&var);
560  }
561  return res;
562 }
563 
564 static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context)
565 {
566  AVFrame *frame_ref;
567  AMFBuffer *frame_ref_storage_buffer = NULL;
568  AMF_RESULT res;
569 
570  res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), &frame_ref_storage_buffer);
571  if (res == AMF_OK) {
572  frame_ref = av_frame_clone(frame);
573  if (frame_ref) {
574  memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), &frame_ref, sizeof(frame_ref));
575  } else {
576  frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
577  frame_ref_storage_buffer = NULL;
578  }
579  }
580  return frame_ref_storage_buffer;
581 }
582 
583 static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer)
584 {
585  AVFrame *frame_ref;
586  memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref));
587  av_frame_free(&frame_ref);
588  frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
589 }
590 
592 {
593  AmfContext *ctx = avctx->priv_data;
594  AMFSurface *surface;
595  AMF_RESULT res;
596  int ret;
597 
598  if (!ctx->encoder)
599  return AVERROR(EINVAL);
600 
601  if (!frame) { // submit drain
602  if (!ctx->eof) { // submit drain one time only
603  if (ctx->delayed_surface != NULL) {
604  ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
605  } else if(!ctx->delayed_drain) {
606  res = ctx->encoder->pVtbl->Drain(ctx->encoder);
607  if (res == AMF_INPUT_FULL) {
608  ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
609  } else {
610  if (res == AMF_OK) {
611  ctx->eof = 1; // drain started
612  }
613  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res);
614  }
615  }
616  } else{
617  return AVERROR_EOF;
618  }
619  } else { // submit frame
620  int hw_surface = 0;
621 
622  if (ctx->delayed_surface != NULL) {
623  return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit
624  }
625  // prepare surface from frame
626  switch (frame->format) {
627 #if CONFIG_D3D11VA
628  case AV_PIX_FMT_D3D11:
629  {
630  static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
631  ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture
632  int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use
633 
634  av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx &&
635  frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data);
636 
637  texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index);
638 
639  res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
640  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res);
641 
642  hw_surface = 1;
643  }
644  break;
645 #endif
646 #if CONFIG_DXVA2
648  {
649  IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture
650 
651  res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
652  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res);
653 
654  hw_surface = 1;
655  }
656  break;
657 #endif
658  default:
659  {
660  res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface);
661  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
662  amf_copy_surface(avctx, frame, surface);
663  }
664  break;
665  }
666 
667  if (hw_surface) {
668  AMFBuffer *frame_ref_storage_buffer;
669 
670  // input HW surfaces can be vertically aligned by 16; tell AMF the real size
671  surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height);
672 
673  frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context);
674  AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n");
675 
676  res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer);
677  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res);
678  ctx->hwsurfaces_in_queue++;
679  frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
680  }
681 
682  surface->pVtbl->SetPts(surface, frame->pts);
683  AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts);
684 
685  switch (avctx->codec->id) {
686  case AV_CODEC_ID_H264:
687  AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud);
688  break;
689  case AV_CODEC_ID_HEVC:
690  AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud);
691  break;
692  default:
693  break;
694  }
695 
696 
697  // submit surface
698  res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
699  if (res == AMF_INPUT_FULL) { // handle full queue
700  //store surface for later submission
701  ctx->delayed_surface = surface;
702  if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) {
703  av_frame_ref(ctx->delayed_frame, frame);
704  }
705  } else {
706  surface->pVtbl->Release(surface);
707  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
708 
709  if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) {
710  return ret;
711  }
712 
713  }
714  }
715  return 0;
716 }
718 {
719  int ret;
720  AMF_RESULT res;
721  AMF_RESULT res_query;
722  AmfContext *ctx = avctx->priv_data;
723  AMFData *data = NULL;
724  int block_and_wait;
725 
726  if (!ctx->encoder)
727  return AVERROR(EINVAL);
728 
729  do {
730  block_and_wait = 0;
731  // poll data
732  res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
733  if (data) {
734  // copy data to packet
735  AMFBuffer* buffer;
736  AMFGuid guid = IID_AMFBuffer();
737  data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
738  ret = amf_copy_buffer(avctx, avpkt, buffer);
739 
740  buffer->pVtbl->Release(buffer);
741 
742  if (data->pVtbl->HasProperty(data, L"av_frame_ref")) {
743  AMFBuffer *frame_ref_storage_buffer;
744  res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer);
745  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res);
746  amf_release_buffer_with_frame_ref(frame_ref_storage_buffer);
747  ctx->hwsurfaces_in_queue--;
748  }
749 
750  data->pVtbl->Release(data);
751 
752  AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
753 
754  if (ctx->delayed_surface != NULL) { // try to resubmit frame
755  res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface);
756  if (res != AMF_INPUT_FULL) {
757  int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface);
758  ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
759  ctx->delayed_surface = NULL;
761  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res);
762 
763  if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) {
764  return ret;
765  }
766  } else {
767  av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n");
768  }
769  } else if (ctx->delayed_drain) { // try to resubmit drain
770  res = ctx->encoder->pVtbl->Drain(ctx->encoder);
771  if (res != AMF_INPUT_FULL) {
772  ctx->delayed_drain = 0;
773  ctx->eof = 1; // drain started
774  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res);
775  } else {
776  av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n");
777  }
778  }
779  } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) {
780  block_and_wait = 1;
781  av_usleep(1000); // wait and poll again
782  }
783  } while (block_and_wait);
784 
785  if (res_query == AMF_EOF) {
786  ret = AVERROR_EOF;
787  } else if (data == NULL) {
788  ret = AVERROR(EAGAIN);
789  } else {
790  ret = 0;
791  }
792  return ret;
793 }
#define AVERROR_ENCODER_NOT_FOUND
Encoder not found.
Definition: error.h:54
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
#define NULL
Definition: coverity.c:32
static int amf_init_encoder(AVCodecContext *avctx)
Definition: amfenc.c:335
const struct AVCodec * codec
Definition: avcodec.h:535
int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
Enlarge an AVFifoBuffer.
Definition: fifo.c:107
AMFContext * context
AMF context.
Definition: amfenc.h:56
static enum AVPixelFormat pix_fmt
int hwsurfaces_in_queue
Definition: amfenc.h:65
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:125
int size
#define FFMPEG_AMF_WRITER_ID
Definition: amfenc.c:48
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
An API-specific header for AV_HWDEVICE_TYPE_D3D11VA.
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Memory handling functions.
An API-specific header for AV_HWDEVICE_TYPE_DXVA2.
int max_b_frames
maximum number of B-frames between non-B-frames Note: The output will be delayed by max_b_frames+1 re...
Definition: avcodec.h:786
AVBufferRef * hw_device_ctx
pointer to HW accelerator (decoder)
Definition: amfenc.h:62
static int amf_init_context(AVCodecContext *avctx)
Definition: amfenc.c:213
int hwsurfaces_in_queue_max
Definition: amfenc.h:66
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:736
#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value,...)
Error handling helper.
Definition: amfenc.h:144
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
static AVPacket pkt
static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, const wchar_t *scope, const wchar_t *message)
Definition: amfenc.c:91
static int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp)
Definition: amfenc.c:434
int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int(*func)(void *, void *, int))
Feed data from a user-supplied callback to an AVFifoBuffer.
Definition: fifo.c:122
AMF_SURFACE_FORMAT format
AMF surface format.
Definition: amfenc.h:60
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:639
static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer)
Definition: amfenc.c:583
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static char buffer[20]
Definition: seek.c:32
uint8_t
#define av_cold
Definition: attributes.h:88
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
Ecoding one frame - common function for all AMF encoders.
Definition: amfenc.c:591
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:444
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:393
int av_fifo_space(const AVFifoBuffer *f)
Return the amount of space in bytes in the AVFifoBuffer, that is the amount of data you can write int...
Definition: fifo.c:82
AVFrame * delayed_frame
Definition: amfenc.h:71
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
const char data[16]
Definition: mxf.c:91
ID3D11Device * device
Device used for texture creation and access.
uint8_t * data
Definition: packet.h:355
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
int delayed_drain
Definition: amfenc.h:69
#define av_log(a,...)
static int amf_load_library(AVCodecContext *avctx)
Definition: amfenc.c:108
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:388
enum AVPixelFormat av_format
Definition: amfenc.c:65
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:88
AMF trace writer callback class Used to capture all AMF logging.
Definition: amfenc.h:37
enum AVCodecID id
Definition: codec.h:204
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
int width
Definition: frame.h:358
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int av_cold ff_amf_encode_close(AVCodecContext *avctx)
Common encoder termination function.
Definition: amfenc.c:369
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
static AMFTraceWriterVtbl tracer_vtbl
Definition: amfenc.c:102
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void(*func)(void *, void *, int))
Feed data from an AVFifoBuffer to a user-supplied callback.
Definition: fifo.c:213
static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val)
Definition: amfenc.c:521
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
simple assert() macros that are a bit more flexible than ISO C assert().
IDirect3DDeviceManager9 * devmgr
static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface *surface)
Definition: amfenc.c:410
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Copy image in src_data to dst_data.
Definition: imgutils.c:387
enum AVPixelFormat ff_amf_pix_fmts[]
Supported formats.
Definition: amfenc.c:52
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:361
static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
Definition: amfenc.c:80
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:199
static const struct @315 planes[]
const char * name
Definition: qsvenc.c:46
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:149
static AMFBuffer * amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context)
Definition: amfenc.c:564
AVCodecContext * avctx
Definition: amfenc.h:39
int ff_amf_encode_init(AVCodecContext *avctx)
Common encoder initization function.
Definition: amfenc.c:506
int width
picture width / height.
Definition: avcodec.h:699
AVBufferRef * hw_frames_ctx
A reference to the AVHWFramesContext describing the input (for encoding) or output (decoding) frames...
Definition: avcodec.h:2226
AVFormatContext * ctx
Definition: movenc.c:48
static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
Definition: amfenc.c:98
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
AMFFactory * factory
pointer to AMF factory
Definition: amfenc.h:50
AVBufferRef * hw_frames_ctx
pointer to HW accelerator (frame allocator)
Definition: amfenc.h:63
#define L(x)
Definition: vp56_arith.h:36
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:541
#define FF_ARRAY_ELEMS(a)
AMFTraceWriterVtbl * vtbl
Definition: amfenc.h:38
static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
Definition: amfenc.c:446
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:373
amf_handle library
handle to DLL library
Definition: amfenc.h:49
#define PTS_PROP
Definition: amfenc.c:50
AMFComponent * encoder
AMF encoder object.
Definition: amfenc.h:58
int av_fifo_size(const AVFifoBuffer *f)
Return the amount of data in bytes in the AVFifoBuffer, that is the amount of data you can read from ...
Definition: fifo.c:77
int aud
Definition: amfenc.h:107
int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void(*func)(void *, void *, int))
Feed data at specific position from an AVFifoBuffer to a user-supplied callback.
Definition: fifo.c:151
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:331
AMFDebug * debug
pointer to AMF debug interface
Definition: amfenc.h:51
int64_t dts_delay
Definition: amfenc.h:75
AVFifoBuffer * timestamp_list
Definition: amfenc.h:74
main external API structure.
Definition: avcodec.h:526
uint8_t * data
The data buffer.
Definition: buffer.h:89
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
amf_bool eof
flag indicating EOF happened
Definition: amfenc.h:59
const char * av_hwdevice_get_type_name(enum AVHWDeviceType type)
Get the string name of an AVHWDeviceType.
Definition: hwcontext.c:92
int index
Definition: gxfenc.c:89
amf_uint64 version
version of AMF runtime
Definition: amfenc.h:54
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Definition: amfenc.c:717
AMF encoder context.
Definition: amfenc.h:46
HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer. ...
Definition: pixfmt.h:137
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:554
static int64_t pts
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
static const FormatMap format_map[]
Definition: amfenc.c:69
Hardware surfaces for Direct3D11.
Definition: pixfmt.h:313
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val)
Definition: amfenc.c:543
common internal api header.
if(ret< 0)
Definition: vf_mcdeint.c:279
AmfTraceWriter tracer
AMF writer registered with AMF.
Definition: amfenc.h:55
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
enum AMF_SURFACE_FORMAT amf_format
Definition: amfenc.c:66
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
void * priv_data
Definition: avcodec.h:553
This struct is allocated as AVHWDeviceContext.hwctx.
AVFifoBuffer * av_fifo_alloc(unsigned int size)
Initialize an AVFifoBuffer.
Definition: fifo.c:43
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: packet.h:354
This struct is allocated as AVHWDeviceContext.hwctx.
int height
Definition: frame.h:358
int log_to_dbg
Definition: amfenc.h:79
AMFSurface * delayed_surface
Definition: amfenc.h:70
void av_fifo_freep(AVFifoBuffer **f)
Free an AVFifoBuffer and reset pointer to NULL.
Definition: fifo.c:63
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:2465
AMFTrace * trace
pointer to AMF trace interface
Definition: amfenc.h:52
AVBufferRef * hw_device_ctx
A reference to the AVHWDeviceContext describing the device which will be used by a hardware encoder/d...
Definition: avcodec.h:2278
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
static double val(void *priv, double ch)
Definition: aeval.c:76
This structure stores compressed data.
Definition: packet.h:332
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:348
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
#define av_unused
Definition: attributes.h:131