FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 #include "libavutil/mem.h"
28 #include "libavutil/pixdesc.h"
29 #include "libavutil/time.h"
30 
31 #include "amfenc.h"
32 #include "internal.h"
33 
34 #if CONFIG_D3D11VA
35 #include <d3d11.h>
36 #endif
37 
38 #ifdef _WIN32
39 #include "compat/w32dlfcn.h"
40 #else
41 #include <dlfcn.h>
42 #endif
43 
44 #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
45 
46 #define PTS_PROP L"PtsProp"
47 
51 #if CONFIG_D3D11VA
53 #endif
55 };
56 
57 typedef struct FormatMap {
59  enum AMF_SURFACE_FORMAT amf_format;
60 } FormatMap;
61 
62 static const FormatMap format_map[] =
63 {
64  { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
65  { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
66  { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
67  { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
68  { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
69  { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
70  { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
71  { AV_PIX_FMT_D3D11, AMF_SURFACE_NV12 },
72 };
73 
74 
76 {
78  return desc->flags & AV_PIX_FMT_FLAG_HWACCEL;
79 }
80 
81 
82 static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
83 {
84  int i;
85  for (i = 0; i < amf_countof(format_map); i++) {
86  if (format_map[i].av_format == fmt) {
87  return format_map[i].amf_format;
88  }
89  }
90  return AMF_SURFACE_UNKNOWN;
91 }
92 
93 static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
94  const wchar_t *scope, const wchar_t *message)
95 {
96  AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
97  av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
98 }
99 
100 static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
101 {
102 }
103 
104 static AMFTraceWriterVtbl tracer_vtbl =
105 {
106  .Write = AMFTraceWriter_Write,
107  .Flush = AMFTraceWriter_Flush,
108 };
109 
111 {
112  AmfContext *ctx = avctx->priv_data;
113  AMFInit_Fn init_fun = NULL;
114  AMFQueryVersion_Fn version_fun = NULL;
115  AMF_RESULT res = AMF_OK;
116 
117  ctx->eof = 0;
118  ctx->delayed_drain = 0;
119  ctx->hw_frames_ctx = NULL;
120  ctx->hw_device_ctx = NULL;
121  ctx->delayed_surface = NULL;
122  ctx->delayed_frame = av_frame_alloc();
123  if (!ctx->delayed_frame) {
124  return AVERROR(ENOMEM);
125  }
126  // hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small
127  ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t));
128  if (!ctx->timestamp_list) {
129  return AVERROR(ENOMEM);
130  }
131  ctx->dts_delay = 0;
132 
133 
134  ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
135  AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL,
136  AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
137 
138  init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME);
139  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);
140 
141  version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
142  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);
143 
144  res = version_fun(&ctx->version);
145  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
146  res = init_fun(AMF_FULL_VERSION, &ctx->factory);
147  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
148  res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace);
149  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
150  res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug);
151  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
152  return 0;
153 }
154 
156 {
157  AmfContext *ctx = avctx->priv_data;
158  AMF_RESULT res = AMF_OK;
159 
160  // confugure AMF logger
161  // the return of these functions indicates old state and do not affect behaviour
162  ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 );
163  if (ctx->log_to_dbg)
164  ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE);
165  ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0);
166  ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE);
167 
168  // connect AMF logger to av_log
169  ctx->tracer.vtbl = &tracer_vtbl;
170  ctx->tracer.avctx = avctx;
171  ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1);
172  ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
173 
174  res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
175  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
176  // try to reuse existing DX device
177 #if CONFIG_D3D11VA
178  if (avctx->hw_frames_ctx) {
179  AVHWFramesContext *device_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
180  if (device_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
181  if (amf_av_to_amf_format(device_ctx->sw_format) != AMF_SURFACE_UNKNOWN) {
182  if (device_ctx->device_ctx->hwctx) {
183  AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->device_ctx->hwctx;
184  res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1);
185  if (res == AMF_OK) {
187  if (!ctx->hw_frames_ctx) {
188  return AVERROR(ENOMEM);
189  }
190  } else {
191  if(res == AMF_NOT_SUPPORTED)
192  av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n");
193  else
194  av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has non-AMD device, switching to default\n");
195  }
196  }
197  } else {
198  av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has format not uspported by AMF, switching to default\n");
199  }
200  }
201  } else if (avctx->hw_device_ctx) {
202  AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data);
203  if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
204  if (device_ctx->hwctx) {
205  AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->hwctx;
206  res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1);
207  if (res == AMF_OK) {
209  if (!ctx->hw_device_ctx) {
210  return AVERROR(ENOMEM);
211  }
212  } else {
213  if (res == AMF_NOT_SUPPORTED)
214  av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n");
215  else
216  av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has non-AMD device, switching to default\n");
217  }
218  }
219  }
220  }
221 #endif
222  if (!ctx->hw_frames_ctx && !ctx->hw_device_ctx) {
223  res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
224  if (res != AMF_OK) {
225  res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
226  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "InitDX9() failed with error %d\n", res);
227  }
228  }
229  return 0;
230 }
231 
233 {
234  AmfContext *ctx = avctx->priv_data;
235  const wchar_t *codec_id = NULL;
236  AMF_RESULT res = AMF_OK;
237 
238  switch (avctx->codec->id) {
239  case AV_CODEC_ID_H264:
240  codec_id = AMFVideoEncoderVCE_AVC;
241  break;
242  case AV_CODEC_ID_HEVC:
243  codec_id = AMFVideoEncoder_HEVC;
244  break;
245  default:
246  break;
247  }
248  AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id);
249 
250  ctx->format = amf_av_to_amf_format(avctx->pix_fmt);
251  AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), "Format %d is not supported\n", avctx->pix_fmt);
252 
253  res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder);
254  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res);
255 
256  return 0;
257 }
258 
260 {
261  AmfContext *ctx = avctx->priv_data;
262  if (ctx->delayed_surface)
263  {
264  ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
265  ctx->delayed_surface = NULL;
266  }
267 
268  if (ctx->encoder) {
269  ctx->encoder->pVtbl->Terminate(ctx->encoder);
270  ctx->encoder->pVtbl->Release(ctx->encoder);
271  ctx->encoder = NULL;
272  }
273 
274  if (ctx->context) {
275  ctx->context->pVtbl->Terminate(ctx->context);
276  ctx->context->pVtbl->Release(ctx->context);
277  ctx->context = NULL;
278  }
281 
282  if (ctx->trace) {
283  ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID);
284  }
285  if (ctx->library) {
286  dlclose(ctx->library);
287  ctx->library = NULL;
288  }
289  ctx->trace = NULL;
290  ctx->debug = NULL;
291  ctx->factory = NULL;
292  ctx->version = 0;
293  ctx->delayed_drain = 0;
296 
297  return 0;
298 }
299 
300 static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
301  AMFSurface* surface)
302 {
303  AVFrame *sw_frame = NULL;
304  AMFPlane *plane = NULL;
305  uint8_t *dst_data[4];
306  int dst_linesize[4];
307  int ret = 0;
308  int planes;
309  int i;
310 
311  if (frame->hw_frames_ctx && is_hwaccel_pix_fmt(frame->format)) {
312  if (!(sw_frame = av_frame_alloc())) {
313  av_log(avctx, AV_LOG_ERROR, "Can not alloc frame\n");
314  ret = AVERROR(ENOMEM);
315  goto fail;
316  }
317  if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {
318  av_log(avctx, AV_LOG_ERROR, "Error transferring the data to system memory\n");
319  goto fail;
320  }
321  frame = sw_frame;
322  }
323  planes = (int)surface->pVtbl->GetPlanesCount(surface);
324  if (planes > amf_countof(dst_data)) {
325  av_log(avctx, AV_LOG_ERROR, "Invalid number of planes %d in surface\n", planes);
326  ret = AVERROR(EINVAL);
327  goto fail;
328  }
329 
330  for (i = 0; i < planes; i++) {
331  plane = surface->pVtbl->GetPlaneAt(surface, i);
332  dst_data[i] = plane->pVtbl->GetNative(plane);
333  dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
334  }
335  av_image_copy(dst_data, dst_linesize,
336  (const uint8_t**)frame->data, frame->linesize, frame->format,
337  avctx->width, avctx->height);
338 
339 fail:
340  if (sw_frame) {
341  av_frame_free(&sw_frame);
342  }
343  return ret;
344 }
345 
346 static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp)
347 {
348  AmfContext *ctx = avctx->priv_data;
349  if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) {
350  if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) {
351  return AVERROR(ENOMEM);
352  }
353  }
354  av_fifo_generic_write(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
355  return 0;
356 }
357 
358 static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
359 {
360  AmfContext *ctx = avctx->priv_data;
361  int ret;
362  AMFVariantStruct var = {0};
363  int64_t timestamp = AV_NOPTS_VALUE;
364  int64_t size = buffer->pVtbl->GetSize(buffer);
365 
366  if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) {
367  return ret;
368  }
369  memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size);
370 
371  switch (avctx->codec->id) {
372  case AV_CODEC_ID_H264:
373  buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var);
374  if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
375  pkt->flags = AV_PKT_FLAG_KEY;
376  }
377  break;
378  case AV_CODEC_ID_HEVC:
379  buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var);
380  if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) {
381  pkt->flags = AV_PKT_FLAG_KEY;
382  }
383  break;
384  default:
385  break;
386  }
387 
388  buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var);
389 
390  pkt->pts = var.int64Value; // original pts
391 
392 
393  AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty\n");
394 
395  av_fifo_generic_read(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
396 
397  // calc dts shift if max_b_frames > 0
398  if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) {
399  int64_t timestamp_last = AV_NOPTS_VALUE;
401  "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames);
403  ctx->timestamp_list,
404  &timestamp_last,
405  (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last),
406  sizeof(timestamp_last),
407  NULL);
408  if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) {
409  return AVERROR(ERANGE);
410  }
411  ctx->dts_delay = timestamp_last - timestamp;
412  }
413  pkt->dts = timestamp - ctx->dts_delay;
414  return 0;
415 }
416 
417 // amfenc API implmentation
419 {
420  AmfContext *ctx = avctx->priv_data;
421  int ret;
422 
423  ctx->factory = NULL;
424  ctx->debug = NULL;
425  ctx->trace = NULL;
426  ctx->context = NULL;
427  ctx->encoder = NULL;
428  ctx->library = NULL;
429  ctx->version = 0;
430  ctx->eof = 0;
431  ctx->format = 0;
432  ctx->tracer.vtbl = NULL;
433  ctx->tracer.avctx = NULL;
434 
435  if ((ret = amf_load_library(avctx)) == 0) {
436  if ((ret = amf_init_context(avctx)) == 0) {
437  if ((ret = amf_init_encoder(avctx)) == 0) {
438  return 0;
439  }
440  }
441  }
442  ff_amf_encode_close(avctx);
443  return ret;
444 }
445 
446 
448 {
449  AMF_RESULT res = AMF_OK;
450  AmfContext *ctx = avctx->priv_data;
451  AMFSurface *surface = NULL;
452  int ret;
453 
454  if (!ctx->encoder)
455  return AVERROR(EINVAL);
456 
457  if (!frame) { // submit drain
458  if (!ctx->eof) { // submit drain one time only
459  if (ctx->delayed_surface != NULL) {
460  ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
461  } else if(!ctx->delayed_drain) {
462  res = ctx->encoder->pVtbl->Drain(ctx->encoder);
463  if (res == AMF_INPUT_FULL) {
464  ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
465  } else {
466  if (res == AMF_OK) {
467  ctx->eof = 1; // drain started
468  }
469  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res);
470  }
471  }
472  } else{
473  return AVERROR_EOF;
474  }
475  } else { // submit frame
476  if (ctx->delayed_surface != NULL) {
477  return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit
478  }
479  // prepare surface from frame
480  if (frame->hw_frames_ctx && ( // HW frame detected
481  // check if the same hw_frames_ctx as used in initialization
482  (ctx->hw_frames_ctx && frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data) ||
483  // check if the same hw_device_ctx as used in initialization
484  (ctx->hw_device_ctx && ((AVHWFramesContext*)frame->hw_frames_ctx->data)->device_ctx ==
486  )) {
487 #if CONFIG_D3D11VA
488  static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
489  ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture
490  int index = (int)(size_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use
491  texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index);
492 
493  res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
494  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res);
495 
496  // input HW surfaces can be vertically aligned by 16; tell AMF the real size
497  surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height);
498 #endif
499  } else {
500  res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface);
501  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
502  amf_copy_surface(avctx, frame, surface);
503  }
504  surface->pVtbl->SetPts(surface, frame->pts);
505  AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts);
506 
507  switch (avctx->codec->id) {
508  case AV_CODEC_ID_H264:
509  AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud);
510  break;
511  case AV_CODEC_ID_HEVC:
512  AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud);
513  break;
514  default:
515  break;
516  }
517 
518 
519  // submit surface
520  res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
521  if (res == AMF_INPUT_FULL) { // handle full queue
522  //store surface for later submission
523  ctx->delayed_surface = surface;
524  if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) {
525  av_frame_ref(ctx->delayed_frame, frame);
526  }
527  } else {
528  surface->pVtbl->Release(surface);
529  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
530 
531  if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) {
532  return ret;
533  }
534 
535  }
536  }
537  return 0;
538 }
540 {
541  int ret;
542  AMF_RESULT res;
543  AMF_RESULT res_query;
544  AmfContext *ctx = avctx->priv_data;
545  AMFData *data = NULL;
546  int block_and_wait;
547 
548  if (!ctx->encoder)
549  return AVERROR(EINVAL);
550 
551  do {
552  block_and_wait = 0;
553  // poll data
554  res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
555  if (data) {
556  // copy data to packet
557  AMFBuffer* buffer;
558  AMFGuid guid = IID_AMFBuffer();
559  data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
560  ret = amf_copy_buffer(avctx, avpkt, buffer);
561 
562  buffer->pVtbl->Release(buffer);
563  data->pVtbl->Release(data);
564 
565  AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
566 
567  if (ctx->delayed_surface != NULL) { // try to resubmit frame
568  res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface);
569  if (res != AMF_INPUT_FULL) {
570  int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface);
571  ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
572  ctx->delayed_surface = NULL;
574  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res);
575 
576  if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) {
577  return ret;
578  }
579  } else {
580  av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n");
581  }
582  } else if (ctx->delayed_drain) { // try to resubmit drain
583  res = ctx->encoder->pVtbl->Drain(ctx->encoder);
584  if (res != AMF_INPUT_FULL) {
585  ctx->delayed_drain = 0;
586  ctx->eof = 1; // drain started
587  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res);
588  } else {
589  av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n");
590  }
591  }
592  } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF)) {
593  block_and_wait = 1;
594  av_usleep(1000); // wait and poll again
595  }
596  } while (block_and_wait);
597 
598  if (res_query == AMF_EOF) {
599  ret = AVERROR_EOF;
600  } else if (data == NULL) {
601  ret = AVERROR(EAGAIN);
602  } else {
603  ret = 0;
604  }
605  return ret;
606 }
#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:59
int plane
Definition: avisynth_c.h:422
#define NULL
Definition: coverity.c:32
static int amf_init_encoder(AVCodecContext *avctx)
Definition: amfenc.c:232
const struct AVCodec * codec
Definition: avcodec.h:1497
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
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
#define FFMPEG_AMF_WRITER_ID
Definition: amfenc.c:44
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2363
This structure describes decoded (raw) audio or video data.
Definition: frame.h:201
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
const char * fmt
Definition: avisynth_c.h:769
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.
const char * desc
Definition: nvenc.c:63
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:1747
AVBufferRef * hw_device_ctx
pointer to HW accelerator (decoder)
Definition: amfenc.h:62
static int amf_init_context(AVCodecContext *avctx)
Definition: amfenc.c:155
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1697
#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value,...)
Error handling helper.
Definition: amfenc.h:141
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:93
static int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp)
Definition: amfenc.c:346
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:538
int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64_t min_size)
Check AVPacket size and/or allocate data.
Definition: encode.c:32
uint8_t
#define av_cold
Definition: attributes.h:82
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:150
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:234
int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
Ecoding one frame - common function for all AMF encoders.
Definition: amfenc.c:447
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:400
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:294
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:68
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:90
ID3D11Device * device
Device used for texture creation and access.
uint8_t * data
Definition: avcodec.h:1400
#define AVERROR_EOF
End of file.
Definition: error.h:55
int delayed_drain
Definition: amfenc.h:66
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
static int amf_load_library(AVCodecContext *avctx)
Definition: amfenc.c:110
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1432
enum AVPixelFormat av_format
Definition: amfenc.c:58
AMF trace writer callback class Used to capture all AMF logging.
Definition: amfenc.h:37
enum AVCodecID id
Definition: avcodec.h:3365
int width
Definition: frame.h:259
#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:259
#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:163
static AMFTraceWriterVtbl tracer_vtbl
Definition: amfenc.c:104
#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
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:85
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition: pixdesc.h:140
simple assert() macros that are a bit more flexible than ISO C assert().
static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface *surface)
Definition: amfenc.c:300
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:77
#define fail()
Definition: checkasm.h:113
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:386
enum AVPixelFormat ff_amf_pix_fmts[]
Supported formats.
Definition: amfenc.c:48
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1406
int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
Copy data to or from a hw surface.
Definition: hwcontext.c:435
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
Definition: amfenc.c:82
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:147
AVCodecContext * avctx
Definition: amfenc.h:39
int ff_amf_encode_init(AVCodecContext *avctx)
Common encoder initization function.
Definition: amfenc.c:418
int width
picture width / height.
Definition: avcodec.h:1660
AVBufferRef * hw_frames_ctx
A reference to the AVHWFramesContext describing the input (for encoding) or output (decoding) frames...
Definition: avcodec.h:3154
AVFormatContext * ctx
Definition: movenc.c:48
static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
Definition: amfenc.c:100
enum AVCodecID codec_id
Definition: vaapi_decode.c:236
AMFFactory * factory
pointer to AMF factory
Definition: amfenc.h:50
AVBufferRef * hw_frames_ctx
pointer to HW accelerator (frame allocator)
Definition: amfenc.h:63
static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt)
Definition: amfenc.c:75
AMFTraceWriterVtbl * vtbl
Definition: amfenc.h:38
static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
Definition: amfenc.c:358
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:274
amf_handle library
handle to DLL library
Definition: amfenc.h:49
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
#define PTS_PROP
Definition: amfenc.c:46
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:104
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:232
AMFDebug * debug
pointer to AMF debug interface
Definition: amfenc.h:51
int64_t dts_delay
Definition: amfenc.h:72
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
AVFifoBuffer * timestamp_list
Definition: amfenc.h:71
main external API structure.
Definition: avcodec.h:1488
uint8_t * data
The data buffer.
Definition: buffer.h:89
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:63
amf_bool eof
flag indicating EOF happened
Definition: amfenc.h:59
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:122
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:236
int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Definition: amfenc.c:539
AMF encoder context.
Definition: amfenc.h:46
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:510
static int64_t pts
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:215
static const FormatMap format_map[]
Definition: amfenc.c:62
Hardware surfaces for Direct3D11.
Definition: pixfmt.h:309
int
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:62
Y , 8bpp.
Definition: pixfmt.h:70
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:59
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
void * priv_data
Definition: avcodec.h:1515
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: avcodec.h:1399
This struct is allocated as AVHWDeviceContext.hwctx.
int height
Definition: frame.h:259
int log_to_dbg
Definition: amfenc.h:76
AMFSurface * delayed_surface
Definition: amfenc.h:67
void av_fifo_freep(AVFifoBuffer **f)
Free an AVFifoBuffer and reset pointer to NULL.
Definition: fifo.c:63
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:3206
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:220
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
This structure stores compressed data.
Definition: avcodec.h:1377
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1393
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
GLuint buffer
Definition: opengl_enc.c:102