FFmpeg
vf_mestimate_d3d12.c
Go to the documentation of this file.
1 /*
2  * D3D12 Hardware-Accelerated Motion Estimation Filter
3  *
4  * Copyright (c) 2025 Advanced Micro Devices, Inc.
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "libavutil/avassert.h"
24 #include "libavutil/buffer.h"
25 #include "libavutil/hwcontext.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/opt.h"
31 #include "libavutil/mem.h"
32 #include "avfilter.h"
33 #include "filters.h"
34 #include "video.h"
35 
36 
37 typedef struct MEstimateD3D12Context {
38  const AVClass *class;
39 
42 
45 
46  ID3D12Device *device;
47  ID3D12VideoDevice1 *video_device;
48  ID3D12VideoMotionEstimator *motion_estimator;
49  ID3D12VideoMotionVectorHeap *motion_vector_heap;
50  ID3D12VideoEncodeCommandList *command_list;
51  ID3D12CommandQueue *command_queue;
52  ID3D12CommandAllocator *command_allocator;
53 
54  // Graphics command list and queue for copy operations
55  ID3D12GraphicsCommandList *copy_command_list;
56  ID3D12CommandAllocator *copy_command_allocator;
57  ID3D12CommandQueue *copy_command_queue;
58 
59  // Synchronization
60  ID3D12Fence *fence;
61  HANDLE fence_event;
62  uint64_t fence_value;
63 
64  // Motion estimation parameters
65  int block_size; // 8 or 16
66  D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE d3d12_block_size;
67  D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION precision;
68 
69  // Frame buffer
73 
74  // Output textures for resolved motion vectors (GPU-side, DEFAULT heap)
75  ID3D12Resource *resolved_mv_texture_back;
76  ID3D12Resource *resolved_mv_texture_fwd;
77 
78  // Readback buffers for CPU access (READBACK heap)
79  ID3D12Resource *readback_buffer_back;
80  ID3D12Resource *readback_buffer_fwd;
82 
85 
87 {
88  MEstimateD3D12Context *s = ctx->priv;
89 
90  s->initialized = 0;
91  s->fence_value = 0;
92 
93  // Validate block size - only 8 and 16 are valid
94  if (s->block_size != 8 && s->block_size != 16) {
95  av_log(ctx, AV_LOG_ERROR, "Invalid block_size %d. Only 8 and 16 are supported.\n", s->block_size);
96  return AVERROR(EINVAL);
97  }
98 
99  // Set D3D12 block size based on user option
100  if (s->block_size == 8)
101  s->d3d12_block_size = D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_8X8;
102  else
103  s->d3d12_block_size = D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_16X16;
104 
105  // Use quarter-pel precision
106  s->precision = D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION_QUARTER_PEL;
107 
108  return 0;
109 }
110 
112 {
113  MEstimateD3D12Context *s = ctx->priv;
114  HRESULT hr;
115  D3D12_COMMAND_QUEUE_DESC queue_desc = {
116  .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
117  .Priority = 0,
118  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
119  .NodeMask = 0,
120  };
121 
122  // Create fence for synchronization
123  hr = ID3D12Device_CreateFence(s->device, 0, D3D12_FENCE_FLAG_NONE,
124  &IID_ID3D12Fence, (void **)&s->fence);
125  if (FAILED(hr)) {
126  av_log(ctx, AV_LOG_ERROR, "Failed to create fence\n");
127  return AVERROR(EINVAL);
128  }
129 
130  s->fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
131  if (!s->fence_event) {
132  av_log(ctx, AV_LOG_ERROR, "Failed to create fence event\n");
133  return AVERROR(EINVAL);
134  }
135 
136  // Create command queue
137  hr = ID3D12Device_CreateCommandQueue(s->device, &queue_desc,
138  &IID_ID3D12CommandQueue, (void **)&s->command_queue);
139  if (FAILED(hr)) {
140  av_log(ctx, AV_LOG_ERROR, "Failed to create command queue\n");
141  return AVERROR(EINVAL);
142  }
143 
144  // Create command allocator
145  hr = ID3D12Device_CreateCommandAllocator(s->device, D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
146  &IID_ID3D12CommandAllocator, (void **)&s->command_allocator);
147  if (FAILED(hr)) {
148  av_log(ctx, AV_LOG_ERROR, "Failed to create command allocator\n");
149  return AVERROR(EINVAL);
150  }
151 
152  // Create command list
153  hr = ID3D12Device_CreateCommandList(s->device, 0, D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
154  s->command_allocator, NULL, &IID_ID3D12VideoEncodeCommandList,
155  (void **)&s->command_list);
156  if (FAILED(hr)) {
157  av_log(ctx, AV_LOG_ERROR, "Failed to create command list\n");
158  return AVERROR(EINVAL);
159  }
160 
161  hr = ID3D12VideoEncodeCommandList_Close(s->command_list);
162  if (FAILED(hr)) {
163  av_log(ctx, AV_LOG_ERROR, "Failed to close command list\n");
164  return AVERROR(EINVAL);
165  }
166 
167  return 0;
168 }
169 
171 {
172  MEstimateD3D12Context *s = ctx->priv;
173  HRESULT hr;
174  D3D12_FEATURE_DATA_VIDEO_MOTION_ESTIMATOR feature_data = {0};
175  D3D12_VIDEO_MOTION_ESTIMATOR_DESC me_desc = {0};
176  D3D12_VIDEO_MOTION_VECTOR_HEAP_DESC heap_desc = {0};
177 
178  // Check if motion estimation is supported
179  // Set the input parameters for what we want to query
180  feature_data.NodeIndex = 0;
181  feature_data.InputFormat = s->frames_ctx->format;
182  feature_data.BlockSizeFlags = 0; // Will be filled by CheckFeatureSupport with supported flags
183  feature_data.PrecisionFlags = 0; // Will be filled by CheckFeatureSupport with supported flags
184  feature_data.SizeRange.MaxWidth = width;
185  feature_data.SizeRange.MaxHeight = height;
186  feature_data.SizeRange.MinWidth = width;
187  feature_data.SizeRange.MinHeight = height;
188 
189  hr = ID3D12VideoDevice1_CheckFeatureSupport(s->video_device,
190  D3D12_FEATURE_VIDEO_MOTION_ESTIMATOR,
191  &feature_data, sizeof(feature_data));
192  if (FAILED(hr)) {
193  av_log(ctx, AV_LOG_ERROR, "Failed to check motion estimator support (hr=0x%lx)\n", (long)hr);
194  return AVERROR(EINVAL);
195  }
196 
197  // Verify the requested features are actually supported (check returned flags)
198  D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_FLAGS requested_block_flag =
199  (s->d3d12_block_size == D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_8X8) ?
200  D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_FLAG_8X8 :
201  D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_FLAG_16X16;
202 
203  if (!(feature_data.BlockSizeFlags & requested_block_flag)) {
204  av_log(ctx, AV_LOG_ERROR, "Requested block size (%dx%d) not supported by device (supported flags: 0x%x)\n",
205  s->block_size, s->block_size, feature_data.BlockSizeFlags);
206  return AVERROR(ENOSYS);
207  }
208 
209  if (!(feature_data.PrecisionFlags & D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION_FLAG_QUARTER_PEL)) {
210  av_log(ctx, AV_LOG_ERROR, "Quarter-pel precision not supported by device (supported flags: 0x%x)\n",
211  feature_data.PrecisionFlags);
212  return AVERROR(ENOSYS);
213  }
214 
215  av_log(ctx, AV_LOG_VERBOSE, "Motion estimator support confirmed: block_size=%dx%d, precision=quarter-pel\n",
216  s->block_size, s->block_size);
217 
218  // Create motion estimator
219  me_desc.NodeMask = 0;
220  me_desc.InputFormat = s->frames_ctx->format;
221  me_desc.BlockSize = s->d3d12_block_size;
222  me_desc.Precision = s->precision;
223  me_desc.SizeRange = feature_data.SizeRange;
224 
225  hr = ID3D12VideoDevice1_CreateVideoMotionEstimator(s->video_device, &me_desc, NULL,
226  &IID_ID3D12VideoMotionEstimator,
227  (void **)&s->motion_estimator);
228  if (FAILED(hr)) {
229  av_log(ctx, AV_LOG_ERROR, "Failed to create motion estimator\n");
230  return AVERROR(EINVAL);
231  }
232 
233  // Create motion vector heap
234  heap_desc.NodeMask = 0;
235  heap_desc.InputFormat = s->frames_ctx->format;
236  heap_desc.BlockSize = s->d3d12_block_size;
237  heap_desc.Precision = s->precision;
238  heap_desc.SizeRange = feature_data.SizeRange;
239 
240  hr = ID3D12VideoDevice1_CreateVideoMotionVectorHeap(s->video_device, &heap_desc, NULL,
241  &IID_ID3D12VideoMotionVectorHeap,
242  (void **)&s->motion_vector_heap);
243  if (FAILED(hr)) {
244  av_log(ctx, AV_LOG_ERROR, "Failed to create motion vector heap\n");
245  return AVERROR(EINVAL);
246  }
247 
248  // Create resolved motion vector textures in DEFAULT heap (GPU writable)
249  // ResolveMotionVectorHeap outputs to TEXTURE2D with DXGI_FORMAT_R16G16_SINT
250  int mb_width = (width + s->block_size - 1) / s->block_size;
251  int mb_height = (height + s->block_size - 1) / s->block_size;
252 
253  D3D12_HEAP_PROPERTIES heap_props_default = {.Type = D3D12_HEAP_TYPE_DEFAULT};
254  D3D12_RESOURCE_DESC texture_desc = {
255  .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
256  .Alignment = 0,
257  .Width = mb_width,
258  .Height = mb_height,
259  .DepthOrArraySize = 1,
260  .MipLevels = 1,
261  .Format = DXGI_FORMAT_R16G16_SINT, // Motion vector format: signed 16-bit X,Y
262  .SampleDesc = {.Count = 1, .Quality = 0},
263  .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
264  .Flags = D3D12_RESOURCE_FLAG_NONE,
265  };
266 
267  hr = ID3D12Device_CreateCommittedResource(s->device, &heap_props_default, D3D12_HEAP_FLAG_NONE,
268  &texture_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
269  &IID_ID3D12Resource, (void **)&s->resolved_mv_texture_back);
270  if (FAILED(hr)) {
271  av_log(ctx, AV_LOG_ERROR, "Failed to create backward motion vector texture (hr=0x%lx)\n", (long)hr);
272  return AVERROR(EINVAL);
273  }
274 
275  hr = ID3D12Device_CreateCommittedResource(s->device, &heap_props_default, D3D12_HEAP_FLAG_NONE,
276  &texture_desc, D3D12_RESOURCE_STATE_COMMON, NULL,
277  &IID_ID3D12Resource, (void **)&s->resolved_mv_texture_fwd);
278  if (FAILED(hr)) {
279  av_log(ctx, AV_LOG_ERROR, "Failed to create forward motion vector texture (hr=0x%lx)\n", (long)hr);
280  return AVERROR(EINVAL);
281  }
282 
283  // Create READBACK buffers for CPU access
284  // Need to calculate proper size accounting for D3D12 row pitch alignment
285  // Get the footprint to determine the actual required buffer size
286  D3D12_PLACED_SUBRESOURCE_FOOTPRINT temp_layout;
287  UINT64 temp_total_size;
288 
289  ID3D12Device_GetCopyableFootprints(s->device, &texture_desc, 0, 1, 0,
290  &temp_layout, NULL, NULL, &temp_total_size);
291 
292  s->readback_buffer_size = temp_total_size;
293 
294  av_log(ctx, AV_LOG_DEBUG, "Readback buffer size: %llu bytes (texture: %dx%d, pitch: %u)\n",
295  (unsigned long long)s->readback_buffer_size, mb_width, mb_height, temp_layout.Footprint.RowPitch);
296 
297  D3D12_HEAP_PROPERTIES heap_props_readback = {.Type = D3D12_HEAP_TYPE_READBACK};
298  D3D12_RESOURCE_DESC buffer_desc = {
299  .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
300  .Alignment = 0,
301  .Width = s->readback_buffer_size,
302  .Height = 1,
303  .DepthOrArraySize = 1,
304  .MipLevels = 1,
305  .Format = DXGI_FORMAT_UNKNOWN,
306  .SampleDesc = {.Count = 1, .Quality = 0},
307  .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
308  .Flags = D3D12_RESOURCE_FLAG_NONE,
309  };
310 
311  hr = ID3D12Device_CreateCommittedResource(s->device, &heap_props_readback, D3D12_HEAP_FLAG_NONE,
312  &buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
313  &IID_ID3D12Resource, (void **)&s->readback_buffer_back);
314  if (FAILED(hr)) {
315  av_log(ctx, AV_LOG_ERROR, "Failed to create backward readback buffer (hr=0x%lx)\n", (long)hr);
316  return AVERROR(EINVAL);
317  }
318 
319  hr = ID3D12Device_CreateCommittedResource(s->device, &heap_props_readback, D3D12_HEAP_FLAG_NONE,
320  &buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
321  &IID_ID3D12Resource, (void **)&s->readback_buffer_fwd);
322  if (FAILED(hr)) {
323  av_log(ctx, AV_LOG_ERROR, "Failed to create forward readback buffer (hr=0x%lx)\n", (long)hr);
324  return AVERROR(EINVAL);
325  }
326 
327  // Create graphics command queue, allocator and list for copy operations
328  D3D12_COMMAND_QUEUE_DESC copy_queue_desc = {
329  .Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
330  .Priority = 0,
331  .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
332  .NodeMask = 0,
333  };
334 
335  hr = ID3D12Device_CreateCommandQueue(s->device, &copy_queue_desc,
336  &IID_ID3D12CommandQueue, (void **)&s->copy_command_queue);
337  if (FAILED(hr)) {
338  av_log(ctx, AV_LOG_ERROR, "Failed to create copy command queue\n");
339  return AVERROR(EINVAL);
340  }
341 
342  hr = ID3D12Device_CreateCommandAllocator(s->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
343  &IID_ID3D12CommandAllocator, (void **)&s->copy_command_allocator);
344  if (FAILED(hr)) {
345  av_log(ctx, AV_LOG_ERROR, "Failed to create copy command allocator\n");
346  return AVERROR(EINVAL);
347  }
348 
349  hr = ID3D12Device_CreateCommandList(s->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
350  s->copy_command_allocator, NULL, &IID_ID3D12GraphicsCommandList,
351  (void **)&s->copy_command_list);
352  if (FAILED(hr)) {
353  av_log(ctx, AV_LOG_ERROR, "Failed to create copy command list\n");
354  return AVERROR(EINVAL);
355  }
356 
357  hr = ID3D12GraphicsCommandList_Close(s->copy_command_list);
358  if (FAILED(hr)) {
359  av_log(ctx, AV_LOG_ERROR, "Failed to close copy command list\n");
360  return AVERROR(EINVAL);
361  }
362 
363  return 0;
364 }
365 
367 {
368  AVFilterContext *ctx = outlink->src;
369  AVFilterLink *inlink = ctx->inputs[0];
371  FilterLink *outl = ff_filter_link(outlink);
372  MEstimateD3D12Context *s = ctx->priv;
373  AVHWFramesContext *hw_frames_ctx;
374  HRESULT hr;
375  int err;
376 
377  if (!inl->hw_frames_ctx) {
378  av_log(ctx, AV_LOG_ERROR, "D3D12 hardware frames context required\n");
379  return AVERROR(EINVAL);
380  }
381 
382  hw_frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data;
383  if (hw_frames_ctx->format != AV_PIX_FMT_D3D12) {
384  av_log(ctx, AV_LOG_ERROR, "Input must be D3D12 frames\n");
385  return AVERROR(EINVAL);
386  }
387 
388  s->hw_frames_ref = av_buffer_ref(inl->hw_frames_ctx);
389  if (!s->hw_frames_ref)
390  return AVERROR(ENOMEM);
391 
392  s->frames_ctx = hw_frames_ctx->hwctx;
393  s->hw_device_ref = av_buffer_ref(hw_frames_ctx->device_ref);
394  if (!s->hw_device_ref)
395  return AVERROR(ENOMEM);
396 
397  s->device_ctx = ((AVHWDeviceContext *)s->hw_device_ref->data)->hwctx;
398  s->device = s->device_ctx->device;
399 
400  // Propagate hardware frames context to output
402  if (!outl->hw_frames_ctx)
403  return AVERROR(ENOMEM);
404 
405  // Query for ID3D12VideoDevice1 interface from the base video device
406  hr = ID3D12VideoDevice_QueryInterface(s->device_ctx->video_device, &IID_ID3D12VideoDevice1,
407  (void **)&s->video_device);
408  if (FAILED(hr)) {
409  av_log(ctx, AV_LOG_ERROR, "ID3D12VideoDevice1 interface not supported\n");
410  return AVERROR(ENOSYS);
411  }
412 
414  if (err < 0)
415  return err;
416 
418  if (err < 0)
419  return err;
420 
421  s->initialized = 1;
422 
423  return 0;
424 }
425 
427 {
428  uint64_t completion = ID3D12Fence_GetCompletedValue(s->fence);
429 
430  if (completion < s->fence_value) {
431  if (FAILED(ID3D12Fence_SetEventOnCompletion(s->fence, s->fence_value, s->fence_event)))
432  return AVERROR(EINVAL);
433  WaitForSingleObjectEx(s->fence_event, INFINITE, FALSE);
434  }
435 
436  return 0;
437 }
438 
439 static inline void d3d12_barrier_transition(D3D12_RESOURCE_BARRIER *barrier,
440  ID3D12Resource *resource,
441  D3D12_RESOURCE_STATES state_before,
442  D3D12_RESOURCE_STATES state_after)
443 {
444  barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
445  barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
446  barrier->Transition.pResource = resource;
447  barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
448  barrier->Transition.StateBefore = state_before;
449  barrier->Transition.StateAfter = state_after;
450 }
451 
452 static void add_mv_data(AVMotionVector *mv, int mb_size,
453  int x, int y, int x_mv, int y_mv, int dir)
454 {
455  mv->w = mb_size;
456  mv->h = mb_size;
457  mv->dst_x = x + (mb_size >> 1);
458  mv->dst_y = y + (mb_size >> 1);
459  mv->src_x = x_mv + (mb_size >> 1);
460  mv->src_y = y_mv + (mb_size >> 1);
461  mv->source = dir ? 1 : -1;
462  mv->flags = 0;
463  mv->motion_x = x_mv - x;
464  mv->motion_y = y_mv - y;
465  mv->motion_scale = 1;
466 }
467 
469 {
470  MEstimateD3D12Context *s = ctx->priv;
471  uint8_t *mapped_data = NULL;
472  HRESULT hr;
473  int err = 0;
474  AVFrameSideData *sd;
475  AVMotionVector *mvs;
476  int mb_x, mb_y, mv_idx;
477  int mb_width, mb_height;
478  int16_t *d3d12_mvs;
479  ID3D12Resource *buffer = (direction == 0) ? s->readback_buffer_back : s->readback_buffer_fwd;
480 
481  // Map the readback buffer
482  hr = ID3D12Resource_Map(buffer, 0, NULL, (void **)&mapped_data);
483  if (FAILED(hr)) {
484  av_log(ctx, AV_LOG_ERROR, "Failed to map readback buffer (dir=%d, hr=0x%lx)\n", direction, (long)hr);
485  return AVERROR(EINVAL);
486  }
487 
488  // Get the motion vector side data
490  if (!sd) {
491  av_log(ctx, AV_LOG_ERROR, "No motion vector side data found\n");
492  ID3D12Resource_Unmap(buffer, 0, NULL);
493  return AVERROR(EINVAL);
494  }
495 
496  mvs = (AVMotionVector *)sd->data;
497  mb_width = (out->width + s->block_size - 1) / s->block_size;
498  mb_height = (out->height + s->block_size - 1) / s->block_size;
499 
500  // Calculate offset for this direction (0 = backward, 1 = forward)
501  mv_idx = direction * mb_width * mb_height;
502 
503  // Parse D3D12 motion vector format
504  // According to Microsoft documentation:
505  // - Format: DXGI_FORMAT_R16G16_SINT (2D texture)
506  // - Data: Signed 16-bit integers
507  // - Units: Quarter-PEL (quarter pixel precision)
508  // - Layout: X component in R channel, Y component in G channel
509  // - Storage: 2D array matching block layout
510  //
511  // Each motion vector is stored as two int16_t values (X, Y) in quarter-pel units
512  // The buffer is organized as a 2D array: [mb_height][mb_width][2]
513 
514  d3d12_mvs = (int16_t *)mapped_data;
515 
516  for (mb_y = 0; mb_y < mb_height; mb_y++) {
517  for (mb_x = 0; mb_x < mb_width; mb_x++) {
518  const int x_mb = mb_x * s->block_size;
519  const int y_mb = mb_y * s->block_size;
520  const int mv_offset = (mb_y * mb_width + mb_x) * 2;
521 
522  // Read motion vector components in quarter-pel units
523  // R component (index 0) = X motion
524  // G component (index 1) = Y motion
525  int16_t mv_x_qpel = d3d12_mvs[mv_offset + 0];
526  int16_t mv_y_qpel = d3d12_mvs[mv_offset + 1];
527 
528  // Convert from quarter-pel to full pixel coordinates
529  // Quarter-pel means the value is 4x the actual pixel displacement
530  // So divide by 4 to get pixel displacement
531  int src_x = x_mb + (mv_x_qpel / 4);
532  int src_y = y_mb + (mv_y_qpel / 4);
533 
534  // Store the motion vector data
535  // This will set dst (current position) and src (where it came from)
536  add_mv_data(&mvs[mv_idx++], s->block_size, x_mb, y_mb, src_x, src_y, direction);
537 
538  av_log(ctx, AV_LOG_TRACE, "Block[%d,%d] dir=%d: MV=(%d,%d) qpel -> (%d,%d) pixels\n",
539  mb_x, mb_y, direction, mv_x_qpel, mv_y_qpel,
540  mv_x_qpel / 4, mv_y_qpel / 4);
541  }
542  }
543 
544  ID3D12Resource_Unmap(buffer, 0, NULL);
545 
546  av_log(ctx, AV_LOG_DEBUG, "Parsed %d motion vectors for direction %d\n",
547  mb_width * mb_height, direction);
548 
549  return err;
550 }
551 
553 {
554  AVFilterContext *ctx = inlink->dst;
555  MEstimateD3D12Context *s = ctx->priv;
556  AVFrame *out;
557  AVFrameSideData *sd;
558  AVD3D12VAFrame *cur_hwframe, *prev_hwframe, *next_hwframe = NULL;
559  HRESULT hr;
560  int err;
561  int mb_width, mb_height, mb_count;
562 
563  if (!s->initialized) {
564  err = mestimate_d3d12_config_props(ctx->outputs[0]);
565  if (err < 0) {
567  return err;
568  }
569  }
570 
571  // Manage frame buffer
572  av_frame_free(&s->prev_frame);
573  s->prev_frame = s->cur_frame;
574  s->cur_frame = s->next_frame;
575  s->next_frame = frame;
576 
577  if (!s->cur_frame) {
578  s->cur_frame = av_frame_clone(frame);
579  if (!s->cur_frame)
580  return AVERROR(ENOMEM);
581  }
582 
583  if (!s->prev_frame)
584  return 0;
585 
586  // Clone current frame for output
587  out = av_frame_clone(s->cur_frame);
588  if (!out)
589  return AVERROR(ENOMEM);
590 
591  mb_width = (frame->width + s->block_size - 1) / s->block_size;
592  mb_height = (frame->height + s->block_size - 1) / s->block_size;
593  mb_count = mb_width * mb_height;
594 
595  // Allocate side data for motion vectors (2 directions)
597  2 * mb_count * sizeof(AVMotionVector));
598  if (!sd) {
599  av_frame_free(&out);
600  return AVERROR(ENOMEM);
601  }
602 
603  // Get hardware frame pointers
604  cur_hwframe = (AVD3D12VAFrame *)s->cur_frame->data[0];
605  prev_hwframe = (AVD3D12VAFrame *)s->prev_frame->data[0];
606  if (s->next_frame)
607  next_hwframe = (AVD3D12VAFrame *)s->next_frame->data[0];
608 
609  // Reset command allocator and list ONCE for both estimations
610  hr = ID3D12CommandAllocator_Reset(s->command_allocator);
611  if (FAILED(hr)) {
612  av_log(ctx, AV_LOG_ERROR, "Failed to reset command allocator\n");
613  av_frame_free(&out);
614  return AVERROR(EINVAL);
615  }
616 
617  hr = ID3D12VideoEncodeCommandList_Reset(s->command_list, s->command_allocator);
618  if (FAILED(hr)) {
619  av_log(ctx, AV_LOG_ERROR, "Failed to reset command list\n");
620  av_frame_free(&out);
621  return AVERROR(EINVAL);
622  }
623 
624  // Transition current and previous frames to VIDEO_ENCODE_READ
625  D3D12_RESOURCE_BARRIER barriers[3];
626  int barrier_count = 2;
627 
628  d3d12_barrier_transition(&barriers[0], cur_hwframe->texture,
629  D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
630  d3d12_barrier_transition(&barriers[1], prev_hwframe->texture,
631  D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
632 
633  if (next_hwframe) {
634  d3d12_barrier_transition(&barriers[2], next_hwframe->texture,
635  D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ);
636  barrier_count = 3;
637  }
638 
639  ID3D12VideoEncodeCommandList_ResourceBarrier(s->command_list, barrier_count, barriers);
640 
641  // Backward motion estimation (cur -> prev)
642  D3D12_VIDEO_MOTION_ESTIMATOR_INPUT input_back = {
643  .pInputTexture2D = cur_hwframe->texture,
644  .InputSubresourceIndex = 0,
645  .pReferenceTexture2D = prev_hwframe->texture,
646  .ReferenceSubresourceIndex = 0,
647  .pHintMotionVectorHeap = NULL,
648  };
649 
650  D3D12_VIDEO_MOTION_ESTIMATOR_OUTPUT output = {
651  .pMotionVectorHeap = s->motion_vector_heap,
652  };
653 
654  ID3D12VideoEncodeCommandList_EstimateMotion(s->command_list, s->motion_estimator,
655  &output, &input_back);
656 
657  D3D12_RESOLVE_VIDEO_MOTION_VECTOR_HEAP_INPUT resolve_input = {
658  .pMotionVectorHeap = s->motion_vector_heap,
659  .PixelWidth = s->cur_frame->width,
660  .PixelHeight = s->cur_frame->height,
661  };
662 
663  D3D12_RESOLVE_VIDEO_MOTION_VECTOR_HEAP_OUTPUT resolve_output_back = {
664  .pMotionVectorTexture2D = s->resolved_mv_texture_back,
665  .MotionVectorCoordinate = {.X = 0, .Y = 0, .Z = 0, .SubresourceIndex = 0},
666  };
667 
668  ID3D12VideoEncodeCommandList_ResolveMotionVectorHeap(s->command_list,
669  &resolve_output_back, &resolve_input);
670 
671  // Copy resolved texture to readback buffer for CPU access
672  // CopyTextureRegion is not available on video encode command list
673  // We'll need to read directly from the resolved texture after GPU sync
674 
675  // Forward motion estimation (cur -> next) if next frame exists
676  if (next_hwframe) {
677  D3D12_VIDEO_MOTION_ESTIMATOR_INPUT input_fwd = {
678  .pInputTexture2D = cur_hwframe->texture,
679  .InputSubresourceIndex = 0,
680  .pReferenceTexture2D = next_hwframe->texture,
681  .ReferenceSubresourceIndex = 0,
682  .pHintMotionVectorHeap = NULL,
683  };
684 
685  ID3D12VideoEncodeCommandList_EstimateMotion(s->command_list, s->motion_estimator,
686  &output, &input_fwd);
687 
688  D3D12_RESOLVE_VIDEO_MOTION_VECTOR_HEAP_OUTPUT resolve_output_fwd = {
689  .pMotionVectorTexture2D = s->resolved_mv_texture_fwd,
690  .MotionVectorCoordinate = {.X = 0, .Y = 0, .Z = 0, .SubresourceIndex = 0},
691  };
692 
693  ID3D12VideoEncodeCommandList_ResolveMotionVectorHeap(s->command_list,
694  &resolve_output_fwd, &resolve_input);
695 
696  // Copy will be done after command list execution
697  }
698 
699  // Transition resources back to COMMON (reuse barriers by swapping states)
700  for (int i = 0; i < barrier_count; i++)
701  FFSWAP(D3D12_RESOURCE_STATES, barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter);
702 
703  ID3D12VideoEncodeCommandList_ResourceBarrier(s->command_list, barrier_count, barriers);
704 
705  // Close command list ONCE
706  hr = ID3D12VideoEncodeCommandList_Close(s->command_list);
707  if (FAILED(hr)) {
708  av_log(ctx, AV_LOG_ERROR, "Failed to close command list (hr=0x%lx)\n", (long)hr);
709  av_frame_free(&out);
710  return AVERROR(EINVAL);
711  }
712 
713  // Wait for input frame sync
714  hr = ID3D12CommandQueue_Wait(s->command_queue, cur_hwframe->sync_ctx.fence,
715  cur_hwframe->sync_ctx.fence_value);
716  if (FAILED(hr)) {
717  av_log(ctx, AV_LOG_ERROR, "Failed to wait for current frame\n");
718  av_frame_free(&out);
719  return AVERROR(EINVAL);
720  }
721 
722  hr = ID3D12CommandQueue_Wait(s->command_queue, prev_hwframe->sync_ctx.fence,
723  prev_hwframe->sync_ctx.fence_value);
724  if (FAILED(hr)) {
725  av_log(ctx, AV_LOG_ERROR, "Failed to wait for previous frame\n");
726  av_frame_free(&out);
727  return AVERROR(EINVAL);
728  }
729 
730  if (next_hwframe) {
731  hr = ID3D12CommandQueue_Wait(s->command_queue, next_hwframe->sync_ctx.fence,
732  next_hwframe->sync_ctx.fence_value);
733  if (FAILED(hr)) {
734  av_log(ctx, AV_LOG_ERROR, "Failed to wait for next frame\n");
735  av_frame_free(&out);
736  return AVERROR(EINVAL);
737  }
738  }
739 
740  // Execute command list ONCE
741  ID3D12CommandQueue_ExecuteCommandLists(s->command_queue, 1, (ID3D12CommandList **)&s->command_list);
742 
743  // Signal completion
744  hr = ID3D12CommandQueue_Signal(s->command_queue, s->fence, ++s->fence_value);
745  if (FAILED(hr)) {
746  av_log(ctx, AV_LOG_ERROR, "Failed to signal fence\n");
747  av_frame_free(&out);
748  return AVERROR(EINVAL);
749  }
750 
751  // Wait for GPU to complete
753  if (err < 0) {
754  av_frame_free(&out);
755  return err;
756  }
757 
758  // Now copy the resolved textures to readback buffers using graphics command list
759  hr = ID3D12CommandAllocator_Reset(s->copy_command_allocator);
760  if (FAILED(hr)) {
761  av_log(ctx, AV_LOG_ERROR, "Failed to reset copy command allocator\n");
762  av_frame_free(&out);
763  return AVERROR(EINVAL);
764  }
765 
766  hr = ID3D12GraphicsCommandList_Reset(s->copy_command_list, s->copy_command_allocator, NULL);
767  if (FAILED(hr)) {
768  av_log(ctx, AV_LOG_ERROR, "Failed to reset copy command list\n");
769  av_frame_free(&out);
770  return AVERROR(EINVAL);
771  }
772 
773  // Transition resolved textures to COPY_SOURCE state
774  D3D12_RESOURCE_BARRIER copy_barriers[2];
775  int copy_barrier_count = 1;
776 
777  d3d12_barrier_transition(&copy_barriers[0], s->resolved_mv_texture_back,
778  D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE);
779 
780  if (s->next_frame) {
781  d3d12_barrier_transition(&copy_barriers[1], s->resolved_mv_texture_fwd,
782  D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE);
783  copy_barrier_count = 2;
784  }
785 
786  ID3D12GraphicsCommandList_ResourceBarrier(s->copy_command_list, copy_barrier_count, copy_barriers);
787 
788  // Get texture layout for backward copy
789  D3D12_RESOURCE_DESC texture_desc_back;
790  D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout_back;
791  UINT64 row_size_back, total_size_back;
792  UINT num_rows_back;
793 
794  // Get the resource description for backward texture
795  s->resolved_mv_texture_back->lpVtbl->GetDesc(s->resolved_mv_texture_back, &texture_desc_back);
796 
797  av_log(ctx, AV_LOG_DEBUG, "Back texture desc: Width=%llu, Height=%u, Format=%d\n",
798  (unsigned long long)texture_desc_back.Width, texture_desc_back.Height, texture_desc_back.Format);
799 
800  // Get the copyable footprints for the backward texture
801  ID3D12Device_GetCopyableFootprints(s->device, &texture_desc_back, 0, 1, 0,
802  &layout_back, &num_rows_back, &row_size_back, &total_size_back);
803 
804  av_log(ctx, AV_LOG_DEBUG, "Back layout: Offset=%llu, Width=%u, Height=%u, Depth=%u, RowPitch=%u\n",
805  (unsigned long long)layout_back.Offset, layout_back.Footprint.Width, layout_back.Footprint.Height,
806  layout_back.Footprint.Depth, layout_back.Footprint.RowPitch);
807 
808  // Copy backward motion vectors
809  D3D12_TEXTURE_COPY_LOCATION src_back = {
810  .pResource = s->resolved_mv_texture_back,
811  .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
812  .SubresourceIndex = 0
813  };
814 
815  D3D12_TEXTURE_COPY_LOCATION dst_back = {
816  .pResource = s->readback_buffer_back,
817  .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
818  .PlacedFootprint = {
819  .Offset = 0,
820  .Footprint = layout_back.Footprint
821  }
822  };
823 
824  av_log(ctx, AV_LOG_DEBUG, "Copying backward MVs...\n");
825  ID3D12GraphicsCommandList_CopyTextureRegion(s->copy_command_list, &dst_back, 0, 0, 0, &src_back, NULL);
826 
827  // Copy forward motion vectors if available
828  if (s->next_frame) {
829  // Get texture layout for forward copy
830  D3D12_RESOURCE_DESC texture_desc_fwd;
831  D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout_fwd;
832  UINT64 row_size_fwd, total_size_fwd;
833  UINT num_rows_fwd;
834 
835  // Get the resource description for forward texture
836  s->resolved_mv_texture_fwd->lpVtbl->GetDesc(s->resolved_mv_texture_fwd, &texture_desc_fwd);
837 
838  av_log(ctx, AV_LOG_DEBUG, "Fwd texture desc: Width=%llu, Height=%u, Format=%d\n",
839  (unsigned long long)texture_desc_fwd.Width, texture_desc_fwd.Height, texture_desc_fwd.Format);
840 
841  // Get the copyable footprints for the forward texture
842  ID3D12Device_GetCopyableFootprints(s->device, &texture_desc_fwd, 0, 1, 0,
843  &layout_fwd, &num_rows_fwd, &row_size_fwd, &total_size_fwd);
844 
845  av_log(ctx, AV_LOG_DEBUG, "Fwd layout: Offset=%llu, Width=%u, Height=%u, Depth=%u, RowPitch=%u\n",
846  (unsigned long long)layout_fwd.Offset, layout_fwd.Footprint.Width, layout_fwd.Footprint.Height,
847  layout_fwd.Footprint.Depth, layout_fwd.Footprint.RowPitch);
848 
849  D3D12_TEXTURE_COPY_LOCATION src_fwd = {
850  .pResource = s->resolved_mv_texture_fwd,
851  .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
852  .SubresourceIndex = 0
853  };
854 
855  D3D12_TEXTURE_COPY_LOCATION dst_fwd = {
856  .pResource = s->readback_buffer_fwd,
857  .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
858  .PlacedFootprint = {
859  .Offset = 0,
860  .Footprint = layout_fwd.Footprint
861  }
862  };
863 
864  av_log(ctx, AV_LOG_DEBUG, "Copying forward MVs...\n");
865  ID3D12GraphicsCommandList_CopyTextureRegion(s->copy_command_list, &dst_fwd, 0, 0, 0, &src_fwd, NULL);
866  }
867 
868  // Transition back to COMMON state (reuse barriers by swapping states)
869  for (int i = 0; i < copy_barrier_count; i++)
870  FFSWAP(D3D12_RESOURCE_STATES, copy_barriers[i].Transition.StateBefore, copy_barriers[i].Transition.StateAfter);
871 
872  ID3D12GraphicsCommandList_ResourceBarrier(s->copy_command_list, copy_barrier_count, copy_barriers);
873 
874  hr = ID3D12GraphicsCommandList_Close(s->copy_command_list);
875  if (FAILED(hr)) {
876  av_log(ctx, AV_LOG_ERROR, "Failed to close copy command list (hr=0x%lx)\n", (long)hr);
877  av_frame_free(&out);
878  return AVERROR(EINVAL);
879  }
880 
881  // Execute copy command list on the copy queue
882  ID3D12CommandQueue_ExecuteCommandLists(s->copy_command_queue, 1, (ID3D12CommandList **)&s->copy_command_list);
883 
884  // Signal and wait for copy completion
885  hr = ID3D12CommandQueue_Signal(s->copy_command_queue, s->fence, ++s->fence_value);
886  if (FAILED(hr)) {
887  av_log(ctx, AV_LOG_ERROR, "Failed to signal fence for copy\n");
888  av_frame_free(&out);
889  return AVERROR(EINVAL);
890  }
891 
893  if (err < 0) {
894  av_frame_free(&out);
895  return err;
896  }
897 
898  // Read motion vectors for both directions
900  if (err < 0) {
901  av_frame_free(&out);
902  return err;
903  }
904 
905  if (s->next_frame) {
907  if (err < 0) {
908  av_frame_free(&out);
909  return err;
910  }
911  }
912 
913  return ff_filter_frame(ctx->outputs[0], out);
914 }
915 
917 {
918  MEstimateD3D12Context *s = ctx->priv;
919 
920  av_frame_free(&s->prev_frame);
921  av_frame_free(&s->cur_frame);
922  av_frame_free(&s->next_frame);
923 
924  D3D12_OBJECT_RELEASE(s->copy_command_list);
925  D3D12_OBJECT_RELEASE(s->copy_command_allocator);
926  D3D12_OBJECT_RELEASE(s->copy_command_queue);
927  D3D12_OBJECT_RELEASE(s->readback_buffer_back);
928  D3D12_OBJECT_RELEASE(s->readback_buffer_fwd);
929  D3D12_OBJECT_RELEASE(s->resolved_mv_texture_back);
930  D3D12_OBJECT_RELEASE(s->resolved_mv_texture_fwd);
931  D3D12_OBJECT_RELEASE(s->motion_vector_heap);
932  D3D12_OBJECT_RELEASE(s->motion_estimator);
933  D3D12_OBJECT_RELEASE(s->command_list);
934  D3D12_OBJECT_RELEASE(s->command_allocator);
935  D3D12_OBJECT_RELEASE(s->command_queue);
936  D3D12_OBJECT_RELEASE(s->fence);
937 
938  if (s->fence_event)
939  CloseHandle(s->fence_event);
940 
941  av_buffer_unref(&s->hw_frames_ref);
942  av_buffer_unref(&s->hw_device_ref);
943 }
944 
946  {
947  .name = "default",
948  .type = AVMEDIA_TYPE_VIDEO,
949  .filter_frame = mestimate_d3d12_filter_frame,
950  },
951 };
952 
954  {
955  .name = "default",
956  .type = AVMEDIA_TYPE_VIDEO,
957  .config_props = mestimate_d3d12_config_props,
958  },
959 };
960 
961 #define OFFSET(x) offsetof(MEstimateD3D12Context, x)
962 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
963 
965  { "mb_size", "macroblock size, only 8 and 16 are supported", OFFSET(block_size), AV_OPT_TYPE_INT, {.i64 = 16}, 8, 16, FLAGS },
966  { NULL }
967 };
968 
969 AVFILTER_DEFINE_CLASS(mestimate_d3d12);
970 
972  .p.name = "mestimate_d3d12",
973  .p.description = NULL_IF_CONFIG_SMALL("Generate motion vectors using D3D12 hardware acceleration."),
974  .p.priv_class = &mestimate_d3d12_class,
976  .priv_size = sizeof(MEstimateD3D12Context),
979  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
983 };
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
MEstimateD3D12Context::fence_value
uint64_t fence_value
Definition: vf_mestimate_d3d12.c:62
out
FILE * out
Definition: movenc.c:55
MEstimateD3D12Context::readback_buffer_fwd
ID3D12Resource * readback_buffer_fwd
Definition: vf_mestimate_d3d12.c:80
av_frame_get_side_data
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition: frame.c:659
av_frame_new_side_data
AVFrameSideData * av_frame_new_side_data(AVFrame *frame, enum AVFrameSideDataType type, size_t size)
Add a new side data to a frame.
Definition: frame.c:647
AVMotionVector
Definition: motion_vector.h:24
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1067
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:200
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:226
mv
static const int8_t mv[256][2]
Definition: 4xm.c:81
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
mestimate_d3d12_sync_gpu
static int mestimate_d3d12_sync_gpu(MEstimateD3D12Context *s)
Definition: vf_mestimate_d3d12.c:426
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:263
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
mestimate_d3d12_init
static int mestimate_d3d12_init(AVFilterContext *ctx)
Definition: vf_mestimate_d3d12.c:86
AVOption
AVOption.
Definition: opt.h:429
MEstimateD3D12Context::readback_buffer_size
size_t readback_buffer_size
Definition: vf_mestimate_d3d12.c:81
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:220
video.h
MEstimateD3D12Context::d3d12_block_size
D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE d3d12_block_size
Definition: vf_mestimate_d3d12.c:66
MEstimateD3D12Context::resolved_mv_texture_fwd
ID3D12Resource * resolved_mv_texture_fwd
Definition: vf_mestimate_d3d12.c:76
mestimate_d3d12_read_motion_vectors
static int mestimate_d3d12_read_motion_vectors(AVFilterContext *ctx, AVFrame *out, int direction)
Definition: vf_mestimate_d3d12.c:468
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:39
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:63
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
av_cold
#define av_cold
Definition: attributes.h:106
MEstimateD3D12Context::copy_command_queue
ID3D12CommandQueue * copy_command_queue
Definition: vf_mestimate_d3d12.c:57
FFFilter
Definition: filters.h:266
motion_vector.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
D3D12_OBJECT_RELEASE
#define D3D12_OBJECT_RELEASE(pInterface)
A release macro used by D3D12 objects highly frequently.
Definition: hwcontext_d3d12va_internal.h:51
FLAGS
#define FLAGS
Definition: vf_mestimate_d3d12.c:962
AVD3D12VAFrame::sync_ctx
AVD3D12VASyncContext sync_ctx
The sync context for the texture.
Definition: hwcontext_d3d12va.h:159
filters.h
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
AVFormatContext * ctx
Definition: movenc.c:49
mestimate_d3d12_uninit
static av_cold void mestimate_d3d12_uninit(AVFilterContext *ctx)
Definition: vf_mestimate_d3d12.c:916
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:483
AVD3D12VASyncContext::fence
ID3D12Fence * fence
D3D12 fence object.
Definition: hwcontext_d3d12va.h:108
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:264
MEstimateD3D12Context::prev_frame
AVFrame * prev_frame
Definition: vf_mestimate_d3d12.c:70
MEstimateD3D12Context::video_device
ID3D12VideoDevice1 * video_device
Definition: vf_mestimate_d3d12.c:47
if
if(ret)
Definition: filter_design.txt:179
MEstimateD3D12Context::copy_command_allocator
ID3D12CommandAllocator * copy_command_allocator
Definition: vf_mestimate_d3d12.c:56
MEstimateD3D12Context::command_queue
ID3D12CommandQueue * command_queue
Definition: vf_mestimate_d3d12.c:51
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
mestimate_d3d12_options
static const AVOption mestimate_d3d12_options[]
Definition: vf_mestimate_d3d12.c:964
av_buffer_unref
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:139
AVHWFramesContext::device_ref
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:129
MEstimateD3D12Context::motion_vector_heap
ID3D12VideoMotionVectorHeap * motion_vector_heap
Definition: vf_mestimate_d3d12.c:49
MEstimateD3D12Context::hw_device_ref
AVBufferRef * hw_device_ref
Definition: vf_mestimate_d3d12.c:40
add_mv_data
static void add_mv_data(AVMotionVector *mv, int mb_size, int x, int y, int x_mv, int y_mv, int dir)
Definition: vf_mestimate_d3d12.c:452
AVD3D12VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d12va.h:172
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
OFFSET
#define OFFSET(x)
Definition: vf_mestimate_d3d12.c:961
AVD3D12VAFrame::texture
ID3D12Resource * texture
The texture in which the frame is located.
Definition: hwcontext_d3d12va.h:144
hwcontext_d3d12va.h
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:198
MEstimateD3D12Context::block_size
int block_size
Definition: vf_mestimate_d3d12.c:65
FF_FILTER_FLAG_HWFRAME_AWARE
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: filters.h:207
mestimate_d3d12_config_props
static int mestimate_d3d12_config_props(AVFilterLink *outlink)
Definition: vf_mestimate_d3d12.c:366
d3d12_barrier_transition
static void d3d12_barrier_transition(D3D12_RESOURCE_BARRIER *barrier, ID3D12Resource *resource, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after)
Definition: vf_mestimate_d3d12.c:439
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:550
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
height
#define height
Definition: dsp.h:89
MEstimateD3D12Context
Definition: vf_mestimate_d3d12.c:37
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(mestimate_d3d12)
AVFILTER_FLAG_HWDEVICE
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition: avfilter.h:188
AVFrameSideData::data
uint8_t * data
Definition: frame.h:284
buffer.h
MEstimateD3D12Context::device_ctx
AVD3D12VADeviceContext * device_ctx
Definition: vf_mestimate_d3d12.c:43
mestimate_d3d12_outputs
static const AVFilterPad mestimate_d3d12_outputs[]
Definition: vf_mestimate_d3d12.c:953
AVD3D12VAFrame
D3D12VA frame descriptor for pool allocation.
Definition: hwcontext_d3d12va.h:138
mestimate_d3d12_create_objects
static int mestimate_d3d12_create_objects(AVFilterContext *ctx)
Definition: vf_mestimate_d3d12.c:111
ff_vf_mestimate_d3d12
const FFFilter ff_vf_mestimate_d3d12
Definition: vf_mestimate_d3d12.c:971
mestimate_d3d12_filter_frame
static int mestimate_d3d12_filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_mestimate_d3d12.c:552
MEstimateD3D12Context::initialized
int initialized
Definition: vf_mestimate_d3d12.c:83
MEstimateD3D12Context::fence_event
HANDLE fence_event
Definition: vf_mestimate_d3d12.c:61
MEstimateD3D12Context::command_list
ID3D12VideoEncodeCommandList * command_list
Definition: vf_mestimate_d3d12.c:50
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
AVD3D12VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d12va.h:43
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
internal.h
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:45
MEstimateD3D12Context::precision
D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION precision
Definition: vf_mestimate_d3d12.c:67
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:153
MEstimateD3D12Context::copy_command_list
ID3D12GraphicsCommandList * copy_command_list
Definition: vf_mestimate_d3d12.c:55
mestimate_d3d12_create_motion_estimator
static int mestimate_d3d12_create_motion_estimator(AVFilterContext *ctx, int width, int height)
Definition: vf_mestimate_d3d12.c:170
MEstimateD3D12Context::fence
ID3D12Fence * fence
Definition: vf_mestimate_d3d12.c:60
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
MEstimateD3D12Context::next_frame
AVFrame * next_frame
Definition: vf_mestimate_d3d12.c:72
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
avfilter.h
AVFILTER_FLAG_METADATA_ONLY
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition: avfilter.h:183
MEstimateD3D12Context::readback_buffer_back
ID3D12Resource * readback_buffer_back
Definition: vf_mestimate_d3d12.c:79
AVFilterContext
An instance of a filter.
Definition: avfilter.h:274
mestimate_d3d12_inputs
static const AVFilterPad mestimate_d3d12_inputs[]
Definition: vf_mestimate_d3d12.c:945
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
FFFilter::p
AVFilter p
The public AVFilter.
Definition: filters.h:270
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AVFrameSideData
Structure to hold side data for an AVFrame.
Definition: frame.h:282
MEstimateD3D12Context::device
ID3D12Device * device
Definition: vf_mestimate_d3d12.c:46
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AV_FRAME_DATA_MOTION_VECTORS
@ AV_FRAME_DATA_MOTION_VECTORS
Motion vectors exported by some codecs (on demand through the export_mvs flag set in the libavcodec A...
Definition: frame.h:97
MEstimateD3D12Context::frames_ctx
AVD3D12VAFramesContext * frames_ctx
Definition: vf_mestimate_d3d12.c:44
MEstimateD3D12Context::motion_estimator
ID3D12VideoMotionEstimator * motion_estimator
Definition: vf_mestimate_d3d12.c:48
AVD3D12VASyncContext::fence_value
uint64_t fence_value
The fence value used for sync.
Definition: hwcontext_d3d12va.h:119
MEstimateD3D12Context::resolved_mv_texture_back
ID3D12Resource * resolved_mv_texture_back
Definition: vf_mestimate_d3d12.c:75
width
#define width
Definition: dsp.h:89
MEstimateD3D12Context::hw_frames_ref
AVBufferRef * hw_frames_ref
Definition: vf_mestimate_d3d12.c:41
hwcontext_d3d12va_internal.h
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: filters.h:253
MEstimateD3D12Context::command_allocator
ID3D12CommandAllocator * command_allocator
Definition: vf_mestimate_d3d12.c:52
MEstimateD3D12Context::cur_frame
AVFrame * cur_frame
Definition: vf_mestimate_d3d12.c:71