34 #define MAX_REFERENCES 8
105 s->processor_configured = 0;
115 if (
s->command_queue &&
s->fence &&
s->fence_event) {
116 fence_value =
s->fence_value;
117 hr = ID3D12CommandQueue_Signal(
s->command_queue,
s->fence, fence_value);
119 UINT64 completed = ID3D12Fence_GetCompletedValue(
s->fence);
120 if (completed < fence_value) {
121 hr = ID3D12Fence_SetEventOnCompletion(
s->fence, fence_value,
s->fence_event);
129 if (
s->fence_event) {
130 CloseHandle(
s->fence_event);
131 s->fence_event =
NULL;
135 ID3D12Fence_Release(
s->fence);
139 if (
s->command_list) {
140 ID3D12VideoProcessCommandList_Release(
s->command_list);
141 s->command_list =
NULL;
144 if (
s->command_allocator) {
145 ID3D12CommandAllocator_Release(
s->command_allocator);
146 s->command_allocator =
NULL;
149 if (
s->video_processor) {
150 ID3D12VideoProcessor_Release(
s->video_processor);
151 s->video_processor =
NULL;
154 if (
s->video_device) {
155 ID3D12VideoDevice_Release(
s->video_device);
156 s->video_device =
NULL;
159 if (
s->command_queue) {
160 ID3D12CommandQueue_Release(
s->command_queue);
161 s->command_queue =
NULL;
167 for (
int i = 0;
i <
s->queue_count;
i++) {
182 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;
184 return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;
186 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020;
189 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
194 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020;
196 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601;
198 return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
211 }
else if (
inlink->time_base.num > 0 &&
inlink->time_base.den > 0) {
226 D3D12_VIDEO_PROCESS_DEINTERLACE_FLAGS mode_flag;
230 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB;
233 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM;
238 if (
s->supported_deint_flags & D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM) {
239 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM;
241 }
else if (
s->supported_deint_flags & D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB) {
242 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB;
245 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB;
252 if (mode_flag != D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB &&
253 !(
s->supported_deint_flags & mode_flag)) {
255 mode_flag = D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB;
268 D3D12_VIDEO_PROCESS_DEINTERLACE_FLAGS deint_mode;
269 D3D12_VIDEO_FIELD_TYPE field_type;
271 s->device = d3d12_hwctx->device;
274 s->width,
s->height);
276 hr = ID3D12Device_QueryInterface(
s->device, &IID_ID3D12VideoDevice, (
void **)&
s->video_device);
282 D3D12_COMMAND_QUEUE_DESC queue_desc = {
283 .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
284 .Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
285 .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
289 hr = ID3D12Device_CreateCommandQueue(
s->device, &queue_desc, &IID_ID3D12CommandQueue, (
void **)&
s->command_queue);
297 field_type = D3D12_VIDEO_FIELD_TYPE_INTERLACED_TOP_FIELD_FIRST;
300 field_type = D3D12_VIDEO_FIELD_TYPE_INTERLACED_BOTTOM_FIELD_FIRST;
305 s->process_support.NodeIndex = 0;
306 s->process_support.InputSample.Format.Format =
s->input_format;
307 s->process_support.InputSample.Format.ColorSpace =
s->input_colorspace;
308 s->process_support.InputSample.Width =
s->width;
309 s->process_support.InputSample.Height =
s->height;
310 s->process_support.InputFrameRate.Numerator =
s->input_framerate.num;
311 s->process_support.InputFrameRate.Denominator =
s->input_framerate.den;
312 s->process_support.InputFieldType = field_type;
313 s->process_support.InputStereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE;
315 s->process_support.OutputFormat.Format =
s->input_format;
316 s->process_support.OutputFormat.ColorSpace =
s->input_colorspace;
317 s->process_support.OutputFrameRate.Numerator =
s->input_framerate.num *
s->field_rate;
318 s->process_support.OutputFrameRate.Denominator =
s->input_framerate.den;
319 s->process_support.OutputStereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE;
321 hr = ID3D12VideoDevice_CheckFeatureSupport(
323 D3D12_FEATURE_VIDEO_PROCESS_SUPPORT,
325 sizeof(
s->process_support)
333 if (!(
s->process_support.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED)) {
339 s->supported_deint_flags =
s->process_support.DeinterlaceSupport;
343 if (!(
s->supported_deint_flags & (D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_BOB |
344 D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM))) {
352 #if CONFIG_D3D12_VIDEO_PROCESS_REFERENCE_INFO
353 D3D12_FEATURE_DATA_VIDEO_PROCESS_REFERENCE_INFO ref_info = {
355 .DeinterlaceMode = deint_mode,
356 .Filters = D3D12_VIDEO_PROCESS_FILTER_FLAG_NONE,
357 .FeatureSupport = D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE,
358 .InputFrameRate = {
s->input_framerate.num,
s->input_framerate.den },
359 .OutputFrameRate = {
s->input_framerate.num *
s->field_rate,
s->input_framerate.den },
360 .EnableAutoProcessing = FALSE,
363 hr = ID3D12VideoDevice_CheckFeatureSupport(
365 D3D12_FEATURE_VIDEO_PROCESS_REFERENCE_INFO,
371 s->num_past_frames = ref_info.PastFrames;
372 s->num_future_frames = ref_info.FutureFrames;
374 "Reference frames from hardware: past=%d, future=%d\n",
375 s->num_past_frames,
s->num_future_frames);
378 "Failed to query reference info (HRESULT 0x%lX), using defaults\n", hr);
379 s->num_past_frames = (deint_mode == D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM) ? 1 : 0;
380 s->num_future_frames = 0;
384 "Reference info query not available in SDK, using defaults\n");
385 s->num_past_frames = (deint_mode == D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_CUSTOM) ? 1 : 0;
386 s->num_future_frames = 0;
390 s->extra_delay_for_timestamps = (
s->field_rate == 2 &&
s->num_future_frames == 0) ? 1 : 0;
392 s->queue_depth =
s->num_past_frames +
s->num_future_frames +
s->extra_delay_for_timestamps + 1;
400 s->current_frame_index =
s->num_past_frames;
403 s->queue_depth,
s->num_past_frames,
s->num_future_frames,
404 s->extra_delay_for_timestamps);
406 D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC processor_output_desc = {
407 .Format =
s->input_format,
408 .ColorSpace =
s->input_colorspace,
409 .AlphaFillMode = D3D12_VIDEO_PROCESS_ALPHA_FILL_MODE_OPAQUE,
410 .AlphaFillModeSourceStreamIndex = 0,
411 .BackgroundColor = { 0.0f, 0.0f, 0.0f, 1.0f },
412 .FrameRate = {
s->input_framerate.num *
s->field_rate,
s->input_framerate.den },
413 .EnableStereo = FALSE,
416 D3D12_VIDEO_PROCESS_INPUT_STREAM_DESC processor_input_desc = {
417 .Format =
s->input_format,
418 .ColorSpace =
s->input_colorspace,
419 .SourceAspectRatio = {
s->width,
s->height },
420 .DestinationAspectRatio = {
s->width,
s->height },
421 .FrameRate = {
s->input_framerate.num,
s->input_framerate.den },
422 .StereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE,
423 .FieldType = field_type,
424 .DeinterlaceMode = deint_mode,
425 .EnableOrientation = FALSE,
426 .FilterFlags = D3D12_VIDEO_PROCESS_FILTER_FLAG_NONE,
428 .MaxWidth =
s->width,
429 .MaxHeight =
s->height,
430 .MinWidth =
s->width,
431 .MinHeight =
s->height
433 .DestinationSizeRange = {
434 .MaxWidth =
s->width,
435 .MaxHeight =
s->height,
436 .MinWidth =
s->width,
437 .MinHeight =
s->height
439 .EnableAlphaBlending = FALSE,
440 .LumaKey = { .Enable = FALSE, .Lower = 0.0f, .Upper = 1.0f },
441 .NumPastFrames =
s->num_past_frames,
442 .NumFutureFrames =
s->num_future_frames,
443 .EnableAutoProcessing = FALSE,
446 hr = ID3D12VideoDevice_CreateVideoProcessor(
449 &processor_output_desc,
451 &processor_input_desc,
452 &IID_ID3D12VideoProcessor,
453 (
void **)&
s->video_processor
461 hr = ID3D12Device_CreateCommandAllocator(
463 D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
464 &IID_ID3D12CommandAllocator,
465 (
void **)&
s->command_allocator
473 hr = ID3D12Device_CreateCommandList(
476 D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
477 s->command_allocator,
479 &IID_ID3D12VideoProcessCommandList,
480 (
void **)&
s->command_list
488 ID3D12VideoProcessCommandList_Close(
s->command_list);
490 hr = ID3D12Device_CreateFence(
s->device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (
void **)&
s->fence);
498 s->fence_event = CreateEvent(
NULL, FALSE, FALSE,
NULL);
499 if (!
s->fence_event) {
504 s->processor_configured = 1;
510 ID3D12Resource *resource,
511 D3D12_RESOURCE_STATES before,
512 D3D12_RESOURCE_STATES after)
514 barriers[(*count)++] = (D3D12_RESOURCE_BARRIER) {
515 .Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
516 .Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
518 .pResource = resource,
519 .Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
520 .StateBefore = before,
555 ID3D12Resource *input_resource = in_d3d12_frame->
texture;
556 ID3D12Resource *output_resource = out_d3d12_frame->
texture;
565 int actual_future = 0;
567 if (queue_idx >= 0) {
570 for (
i = 0;
i <
s->num_past_frames && (queue_idx - 1 -
i) >= 0;
i++) {
571 AVFrame *past_frame =
s->frame_queue[queue_idx - 1 -
i];
574 past_textures[actual_past] = past_d3d12->
texture;
575 past_subresources[actual_past] = 0;
582 for (
i = 0;
i <
s->num_future_frames && (queue_idx + 1 +
i) <
s->queue_count;
i++) {
583 AVFrame *future_frame =
s->frame_queue[queue_idx + 1 +
i];
586 future_textures[actual_future] = future_d3d12->
texture;
587 future_subresources[actual_future] = 0;
593 "Reference frames: past=%d/%d, future=%d/%d, queue_idx=%d\n",
594 actual_past,
s->num_past_frames, actual_future,
s->num_future_frames,
600 UINT64 completed = ID3D12Fence_GetCompletedValue(in_d3d12_frame->
sync_ctx.
fence);
601 if (completed < in_d3d12_frame->sync_ctx.fence_value) {
602 hr = ID3D12CommandQueue_Wait(
s->command_queue, in_d3d12_frame->
sync_ctx.
fence,
613 for (
i = 0;
i < actual_past;
i++) {
614 AVFrame *past_frame =
s->frame_queue[queue_idx - 1 -
i];
617 hr = ID3D12CommandQueue_Wait(
s->command_queue, past_d3d12->
sync_ctx.
fence,
627 for (
i = 0;
i < actual_future;
i++) {
628 AVFrame *future_frame =
s->frame_queue[queue_idx + 1 +
i];
631 hr = ID3D12CommandQueue_Wait(
s->command_queue, future_d3d12->
sync_ctx.
fence,
641 hr = ID3D12CommandAllocator_Reset(
s->command_allocator);
648 hr = ID3D12VideoProcessCommandList_Reset(
s->command_list,
s->command_allocator);
657 int num_barriers = 0;
660 D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_PROCESS_READ);
662 D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_PROCESS_WRITE);
664 for (
i = 0;
i < actual_past;
i++)
666 D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_PROCESS_READ);
668 for (
i = 0;
i < actual_future;
i++)
670 D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_PROCESS_READ);
672 ID3D12VideoProcessCommandList_ResourceBarrier(
s->command_list, num_barriers, barriers);
675 D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS input_args = {0};
677 input_args.InputStream[0].pTexture2D = input_resource;
680 input_args.InputStream[0].ReferenceSet.NumPastFrames = actual_past;
681 input_args.InputStream[0].ReferenceSet.ppPastFrames = actual_past > 0 ? past_textures :
NULL;
682 input_args.InputStream[0].ReferenceSet.pPastSubresources = actual_past > 0 ? past_subresources :
NULL;
683 input_args.InputStream[0].ReferenceSet.NumFutureFrames = actual_future;
684 input_args.InputStream[0].ReferenceSet.ppFutureFrames = actual_future > 0 ? future_textures :
NULL;
685 input_args.InputStream[0].ReferenceSet.pFutureSubresources = actual_future > 0 ? future_subresources :
NULL;
687 input_args.Transform.SourceRectangle.right =
s->width;
688 input_args.Transform.SourceRectangle.bottom =
s->height;
689 input_args.Transform.DestinationRectangle.right =
s->width;
690 input_args.Transform.DestinationRectangle.bottom =
s->height;
691 input_args.Transform.Orientation = D3D12_VIDEO_PROCESS_ORIENTATION_DEFAULT;
693 input_args.Flags = D3D12_VIDEO_PROCESS_INPUT_STREAM_FLAG_NONE;
695 input_args.RateInfo.OutputIndex =
field;
696 input_args.RateInfo.InputFrameOrField = 0;
698 memset(input_args.FilterLevels, 0,
sizeof(input_args.FilterLevels));
700 input_args.AlphaBlending.Enable = FALSE;
701 input_args.AlphaBlending.Alpha = 1.0f;
704 D3D12_VIDEO_PROCESS_OUTPUT_STREAM_ARGUMENTS output_args = {0};
706 output_args.OutputStream[0].pTexture2D = output_resource;
707 output_args.TargetRectangle.right =
s->width;
708 output_args.TargetRectangle.bottom =
s->height;
710 ID3D12VideoProcessCommandList_ProcessFrames(
719 for (
i = 0;
i < num_barriers;
i++) {
720 FFSWAP(D3D12_RESOURCE_STATES, barriers[
i].Transition.StateBefore, barriers[
i].Transition.StateAfter);
722 ID3D12VideoProcessCommandList_ResourceBarrier(
s->command_list, num_barriers, barriers);
724 hr = ID3D12VideoProcessCommandList_Close(
s->command_list);
731 ID3D12CommandList *cmd_lists[] = { (ID3D12CommandList *)
s->command_list };
732 ID3D12CommandQueue_ExecuteCommandLists(
s->command_queue, 1, cmd_lists);
734 hr = ID3D12CommandQueue_Signal(
s->command_queue,
s->fence,
s->fence_value);
743 ID3D12Fence_AddRef(
s->fence);
753 out->width =
s->width;
754 out->height =
s->height;
759 if (
s->field_rate == 2 && queue_idx >= 0) {
760 AVFrame *next_frame = (queue_idx + 1 <
s->queue_count) ?
761 s->frame_queue[queue_idx + 1] :
NULL;
764 out->pts = 2 * input_frame->
pts;
765 }
else if (
s->eof || !next_frame) {
766 out->pts = 3 * input_frame->
pts -
s->prev_pts;
768 out->pts = input_frame->
pts + next_frame->
pts;
797 if (
s->eof &&
s->queue_count > 0) {
800 if (!
s->initial_fill_done) {
805 "EOF flush (short stream): processing all %d buffered frames\n",
810 flush_idx =
s->current_frame_index + 1;
812 "EOF flush: processing frames %d..%d in queue (count=%d)\n",
813 flush_idx,
s->queue_count - 1,
s->queue_count);
816 while (flush_idx < s->queue_count) {
817 input_frame =
s->frame_queue[flush_idx];
824 s->prev_pts = input_frame->
pts;
844 if (!
s->processor_configured) {
848 s->width = frames_ctx->
width;
849 s->height = frames_ctx->
height;
850 s->input_format = input_hwctx->format;
852 if (
s->input_format == DXGI_FORMAT_UNKNOWN) {
855 s->input_format = DXGI_FORMAT_NV12;
858 s->input_format = DXGI_FORMAT_P010;
868 int is_10bit = (
s->input_format == DXGI_FORMAT_P010);
911 if (
s->queue_count <
s->queue_depth) {
914 s->frame_queue[
s->queue_count++] = in;
915 if (
s->queue_count <
s->queue_depth)
922 for (
int i = 0;
i <=
s->current_frame_index;
i++) {
923 input_frame =
s->frame_queue[
i];
931 s->prev_pts = input_frame->
pts;
933 s->initial_fill_done = 1;
941 for (
int i = 0;
i + 1 <
s->queue_count;
i++)
942 s->frame_queue[
i] =
s->frame_queue[
i + 1];
943 s->frame_queue[
s->queue_count - 1] = in;
945 input_frame =
s->frame_queue[
s->current_frame_index];
955 s->prev_pts = input_frame->
pts;
995 s->processor_configured = 0;
1013 if (!
s->hw_device_ctx) {
1019 if (!
s->hw_frames_ctx_out)
1026 frames_ctx->
width =
s->width;
1027 frames_ctx->
height =
s->height;
1030 if (
ctx->extra_hw_frames > 0)
1037 frames_hwctx->
resource_flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1038 frames_hwctx->
heap_flags = D3D12_HEAP_FLAG_NONE;
1051 outlink->
w, outlink->
h,
s->field_rate);
1084 #define OFFSET(x) offsetof(DeinterlaceD3D12Context, x)
1085 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
1088 {
"mode",
"Deinterlacing mode",
1091 {
"default",
"Use best available deinterlacing mode",
1093 {
"bob",
"Bob deinterlacing (simple field interpolation)",
1095 {
"custom",
"Driver-defined advanced deinterlacing",
1098 {
"rate",
"Generate output at frame rate or field rate",
1100 {
"frame",
"Output at frame rate (one frame for each field-pair)",
1102 {
"field",
"Output at field rate (one frame for each field)",
1105 {
"auto",
"Only deinterlace interlaced frames, pass through progressive",
1114 .
p.
name =
"deinterlace_d3d12",
1117 .
p.priv_class = &deinterlace_d3d12_class,