Browse code

vf_deinterlace_vaapi: Add support for field rate output

In order to work correctly with the i965 driver, this also fixes the
direction of forward/backward references - forward references are
intended to be those from the past to the current frame, not from the
current frame to the future.

(cherry picked from commit 9aa251c98ce60e5ee83156e5292547a7671ced3a)

Mark Thompson authored on 2017/02/28 06:29:46
Showing 1 changed files
... ...
@@ -22,6 +22,7 @@
22 22
 #include <va/va_vpp.h>
23 23
 
24 24
 #include "libavutil/avassert.h"
25
+#include "libavutil/common.h"
25 26
 #include "libavutil/hwcontext.h"
26 27
 #include "libavutil/hwcontext_vaapi.h"
27 28
 #include "libavutil/mem.h"
... ...
@@ -42,6 +43,8 @@ typedef struct DeintVAAPIContext {
42 42
     AVBufferRef       *device_ref;
43 43
 
44 44
     int                mode;
45
+    int                field_rate;
46
+    int                auto_enable;
45 47
 
46 48
     int                valid_ids;
47 49
     VAConfigID         va_config;
... ...
@@ -63,6 +66,7 @@ typedef struct DeintVAAPIContext {
63 63
     int                queue_depth;
64 64
     int                queue_count;
65 65
     AVFrame           *frame_queue[MAX_REFERENCES];
66
+    int                extra_delay_for_timestamps;
66 67
 
67 68
     VABufferID         filter_buffer;
68 69
 } DeintVAAPIContext;
... ...
@@ -211,8 +215,12 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
211 211
         return AVERROR(EIO);
212 212
     }
213 213
 
214
+    ctx->extra_delay_for_timestamps = ctx->field_rate == 2 &&
215
+        ctx->pipeline_caps.num_backward_references == 0;
216
+
214 217
     ctx->queue_depth = ctx->pipeline_caps.num_backward_references +
215
-                       ctx->pipeline_caps.num_forward_references + 1;
218
+                       ctx->pipeline_caps.num_forward_references +
219
+                       ctx->extra_delay_for_timestamps + 1;
216 220
     if (ctx->queue_depth > MAX_REFERENCES) {
217 221
         av_log(avctx, AV_LOG_ERROR, "Pipeline requires too many "
218 222
                "references (%u forward, %u back).\n",
... ...
@@ -227,6 +235,7 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
227 227
 static int deint_vaapi_config_output(AVFilterLink *outlink)
228 228
 {
229 229
     AVFilterContext    *avctx = outlink->src;
230
+    AVFilterLink      *inlink = avctx->inputs[0];
230 231
     DeintVAAPIContext    *ctx = avctx->priv;
231 232
     AVVAAPIHWConfig *hwconfig = NULL;
232 233
     AVHWFramesConstraints *constraints = NULL;
... ...
@@ -326,8 +335,13 @@ static int deint_vaapi_config_output(AVFilterLink *outlink)
326 326
     if (err < 0)
327 327
         goto fail;
328 328
 
329
-    outlink->w = ctx->output_width;
330
-    outlink->h = ctx->output_height;
329
+    outlink->w = inlink->w;
330
+    outlink->h = inlink->h;
331
+
332
+    outlink->time_base  = av_mul_q(inlink->time_base,
333
+                                   (AVRational) { 1, ctx->field_rate });
334
+    outlink->frame_rate = av_mul_q(inlink->frame_rate,
335
+                                   (AVRational) { ctx->field_rate, 1 });
331 336
 
332 337
     outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref);
333 338
     if (!outlink->hw_frames_ctx) {
... ...
@@ -375,7 +389,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
375 375
     VABufferID params_id;
376 376
     VAStatus vas;
377 377
     void *filter_params_addr = NULL;
378
-    int err, i;
378
+    int err, i, field, current_frame_index;
379 379
 
380 380
     av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
381 381
            av_get_pix_fmt_name(input_frame->format),
... ...
@@ -394,17 +408,16 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
394 394
         ctx->frame_queue[i] = input_frame;
395 395
     }
396 396
 
397
-    input_frame =
398
-        ctx->frame_queue[ctx->pipeline_caps.num_backward_references];
397
+    current_frame_index = ctx->pipeline_caps.num_forward_references;
398
+
399
+    input_frame = ctx->frame_queue[current_frame_index];
399 400
     input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3];
400
-    for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
401
-        backward_references[i] = (VASurfaceID)(uintptr_t)
402
-            ctx->frame_queue[ctx->pipeline_caps.num_backward_references -
403
-                             i - 1]->data[3];
404 401
     for (i = 0; i < ctx->pipeline_caps.num_forward_references; i++)
405 402
         forward_references[i] = (VASurfaceID)(uintptr_t)
406
-            ctx->frame_queue[ctx->pipeline_caps.num_backward_references +
407
-                             i + 1]->data[3];
403
+            ctx->frame_queue[current_frame_index - i - 1]->data[3];
404
+    for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
405
+        backward_references[i] = (VASurfaceID)(uintptr_t)
406
+            ctx->frame_queue[current_frame_index + i + 1]->data[3];
408 407
 
409 408
     av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
410 409
            "deinterlace input.\n", input_surface);
... ...
@@ -417,129 +430,148 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
417 417
         av_log(avctx, AV_LOG_DEBUG, " %#x", forward_references[i]);
418 418
     av_log(avctx, AV_LOG_DEBUG, "\n");
419 419
 
420
-    output_frame = av_frame_alloc();
421
-    if (!output_frame) {
422
-        err = AVERROR(ENOMEM);
423
-        goto fail;
424
-    }
425
-
426
-    err = av_hwframe_get_buffer(ctx->output_frames_ref,
427
-                                output_frame, 0);
428
-    if (err < 0) {
429
-        err = AVERROR(ENOMEM);
430
-        goto fail;
431
-    }
432
-
433
-    output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
434
-    av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
435
-           "deinterlace output.\n", output_surface);
436
-
437
-    memset(&params, 0, sizeof(params));
438
-
439
-    input_region = (VARectangle) {
440
-        .x      = 0,
441
-        .y      = 0,
442
-        .width  = input_frame->width,
443
-        .height = input_frame->height,
444
-    };
420
+    for (field = 0; field < ctx->field_rate; field++) {
421
+        output_frame = ff_get_video_buffer(outlink, ctx->output_width,
422
+                                           ctx->output_height);
423
+        if (!output_frame) {
424
+            err = AVERROR(ENOMEM);
425
+            goto fail;
426
+        }
445 427
 
446
-    params.surface = input_surface;
447
-    params.surface_region = &input_region;
448
-    params.surface_color_standard = vaapi_proc_colour_standard(
449
-        input_frame->colorspace);
428
+        output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
429
+        av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
430
+               "deinterlace output.\n", output_surface);
431
+
432
+        memset(&params, 0, sizeof(params));
433
+
434
+        input_region = (VARectangle) {
435
+            .x      = 0,
436
+            .y      = 0,
437
+            .width  = input_frame->width,
438
+            .height = input_frame->height,
439
+        };
440
+
441
+        params.surface = input_surface;
442
+        params.surface_region = &input_region;
443
+        params.surface_color_standard =
444
+            vaapi_proc_colour_standard(input_frame->colorspace);
445
+
446
+        params.output_region = NULL;
447
+        params.output_background_color = 0xff000000;
448
+        params.output_color_standard = params.surface_color_standard;
449
+
450
+        params.pipeline_flags = 0;
451
+        params.filter_flags   = VA_FRAME_PICTURE;
452
+
453
+        if (!ctx->auto_enable || input_frame->interlaced_frame) {
454
+            vas = vaMapBuffer(ctx->hwctx->display, ctx->filter_buffer,
455
+                              &filter_params_addr);
456
+            if (vas != VA_STATUS_SUCCESS) {
457
+                av_log(avctx, AV_LOG_ERROR, "Failed to map filter parameter "
458
+                       "buffer: %d (%s).\n", vas, vaErrorStr(vas));
459
+                err = AVERROR(EIO);
460
+                goto fail;
461
+            }
462
+            filter_params = filter_params_addr;
463
+            filter_params->flags = 0;
464
+            if (input_frame->top_field_first) {
465
+                filter_params->flags |= field ? VA_DEINTERLACING_BOTTOM_FIELD : 0;
466
+            } else {
467
+                filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
468
+                filter_params->flags |= field ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
469
+            }
470
+            filter_params_addr = NULL;
471
+            vas = vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer);
472
+            if (vas != VA_STATUS_SUCCESS)
473
+                av_log(avctx, AV_LOG_ERROR, "Failed to unmap filter parameter "
474
+                       "buffer: %d (%s).\n", vas, vaErrorStr(vas));
475
+
476
+            params.filters     = &ctx->filter_buffer;
477
+            params.num_filters = 1;
478
+
479
+            params.forward_references = forward_references;
480
+            params.num_forward_references =
481
+                ctx->pipeline_caps.num_forward_references;
482
+            params.backward_references = backward_references;
483
+            params.num_backward_references =
484
+                ctx->pipeline_caps.num_backward_references;
485
+
486
+        } else {
487
+            params.filters     = NULL;
488
+            params.num_filters = 0;
489
+        }
450 490
 
451
-    params.output_region = NULL;
452
-    params.output_background_color = 0xff000000;
453
-    params.output_color_standard = params.surface_color_standard;
491
+        vas = vaBeginPicture(ctx->hwctx->display,
492
+                             ctx->va_context, output_surface);
493
+        if (vas != VA_STATUS_SUCCESS) {
494
+            av_log(avctx, AV_LOG_ERROR, "Failed to attach new picture: "
495
+                   "%d (%s).\n", vas, vaErrorStr(vas));
496
+            err = AVERROR(EIO);
497
+            goto fail;
498
+        }
454 499
 
455
-    params.pipeline_flags = 0;
456
-    params.filter_flags   = VA_FRAME_PICTURE;
500
+        vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
501
+                             VAProcPipelineParameterBufferType,
502
+                             sizeof(params), 1, &params, &params_id);
503
+        if (vas != VA_STATUS_SUCCESS) {
504
+            av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer: "
505
+                   "%d (%s).\n", vas, vaErrorStr(vas));
506
+            err = AVERROR(EIO);
507
+            goto fail_after_begin;
508
+        }
509
+        av_log(avctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n",
510
+               params_id);
457 511
 
458
-    vas = vaMapBuffer(ctx->hwctx->display, ctx->filter_buffer,
459
-                      &filter_params_addr);
460
-    if (vas != VA_STATUS_SUCCESS) {
461
-        av_log(avctx, AV_LOG_ERROR, "Failed to map filter parameter "
462
-               "buffer: %d (%s).\n", vas, vaErrorStr(vas));
463
-        err = AVERROR(EIO);
464
-        goto fail;
465
-    }
466
-    filter_params = filter_params_addr;
467
-    filter_params->flags = 0;
468
-    if (input_frame->interlaced_frame && !input_frame->top_field_first)
469
-        filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
470
-    filter_params_addr = NULL;
471
-    vas = vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer);
472
-    if (vas != VA_STATUS_SUCCESS)
473
-        av_log(avctx, AV_LOG_ERROR, "Failed to unmap filter parameter "
474
-               "buffer: %d (%s).\n", vas, vaErrorStr(vas));
475
-
476
-    params.filters     = &ctx->filter_buffer;
477
-    params.num_filters = 1;
478
-
479
-    params.forward_references = forward_references;
480
-    params.num_forward_references =
481
-        ctx->pipeline_caps.num_forward_references;
482
-    params.backward_references = backward_references;
483
-    params.num_backward_references =
484
-        ctx->pipeline_caps.num_backward_references;
485
-
486
-    vas = vaBeginPicture(ctx->hwctx->display,
487
-                         ctx->va_context, output_surface);
488
-    if (vas != VA_STATUS_SUCCESS) {
489
-        av_log(avctx, AV_LOG_ERROR, "Failed to attach new picture: "
490
-               "%d (%s).\n", vas, vaErrorStr(vas));
491
-        err = AVERROR(EIO);
492
-        goto fail;
493
-    }
512
+        vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
513
+                              &params_id, 1);
514
+        if (vas != VA_STATUS_SUCCESS) {
515
+            av_log(avctx, AV_LOG_ERROR, "Failed to render parameter buffer: "
516
+                   "%d (%s).\n", vas, vaErrorStr(vas));
517
+            err = AVERROR(EIO);
518
+            goto fail_after_begin;
519
+        }
494 520
 
495
-    vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
496
-                         VAProcPipelineParameterBufferType,
497
-                         sizeof(params), 1, &params, &params_id);
498
-    if (vas != VA_STATUS_SUCCESS) {
499
-        av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer: "
500
-               "%d (%s).\n", vas, vaErrorStr(vas));
501
-        err = AVERROR(EIO);
502
-        goto fail_after_begin;
503
-    }
504
-    av_log(avctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n",
505
-           params_id);
521
+        vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
522
+        if (vas != VA_STATUS_SUCCESS) {
523
+            av_log(avctx, AV_LOG_ERROR, "Failed to start picture processing: "
524
+                   "%d (%s).\n", vas, vaErrorStr(vas));
525
+            err = AVERROR(EIO);
526
+            goto fail_after_render;
527
+        }
506 528
 
507
-    vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
508
-                          &params_id, 1);
509
-    if (vas != VA_STATUS_SUCCESS) {
510
-        av_log(avctx, AV_LOG_ERROR, "Failed to render parameter buffer: "
511
-               "%d (%s).\n", vas, vaErrorStr(vas));
512
-        err = AVERROR(EIO);
513
-        goto fail_after_begin;
514
-    }
529
+        if (ctx->hwctx->driver_quirks &
530
+            AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) {
531
+            vas = vaDestroyBuffer(ctx->hwctx->display, params_id);
532
+            if (vas != VA_STATUS_SUCCESS) {
533
+                av_log(avctx, AV_LOG_ERROR, "Failed to free parameter buffer: "
534
+                       "%d (%s).\n", vas, vaErrorStr(vas));
535
+                // And ignore.
536
+            }
537
+        }
515 538
 
516
-    vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
517
-    if (vas != VA_STATUS_SUCCESS) {
518
-        av_log(avctx, AV_LOG_ERROR, "Failed to start picture processing: "
519
-               "%d (%s).\n", vas, vaErrorStr(vas));
520
-        err = AVERROR(EIO);
521
-        goto fail_after_render;
522
-    }
539
+        err = av_frame_copy_props(output_frame, input_frame);
540
+        if (err < 0)
541
+            goto fail;
523 542
 
524
-    if (ctx->hwctx->driver_quirks &
525
-        AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) {
526
-        vas = vaDestroyBuffer(ctx->hwctx->display, params_id);
527
-        if (vas != VA_STATUS_SUCCESS) {
528
-            av_log(avctx, AV_LOG_ERROR, "Failed to free parameter buffer: "
529
-                   "%d (%s).\n", vas, vaErrorStr(vas));
530
-            // And ignore.
543
+        if (ctx->field_rate == 2) {
544
+            if (field == 0)
545
+                output_frame->pts = 2 * input_frame->pts;
546
+            else
547
+                output_frame->pts = input_frame->pts +
548
+                    ctx->frame_queue[current_frame_index + 1]->pts;
531 549
         }
532
-    }
550
+        output_frame->interlaced_frame = 0;
533 551
 
534
-    err = av_frame_copy_props(output_frame, input_frame);
535
-    if (err < 0)
536
-        goto fail;
552
+        av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
553
+               av_get_pix_fmt_name(output_frame->format),
554
+               output_frame->width, output_frame->height, output_frame->pts);
537 555
 
538
-    av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
539
-           av_get_pix_fmt_name(output_frame->format),
540
-           output_frame->width, output_frame->height, output_frame->pts);
556
+        err = ff_filter_frame(outlink, output_frame);
557
+        if (err < 0)
558
+            break;
559
+    }
541 560
 
542
-    return ff_filter_frame(outlink, output_frame);
561
+    return err;
543 562
 
544 563
 fail_after_begin:
545 564
     vaRenderPicture(ctx->hwctx->display, ctx->va_context, &params_id, 1);
... ...
@@ -592,6 +624,17 @@ static const AVOption deint_vaapi_options[] = {
592 592
       0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, .unit = "mode" },
593 593
     { "motion_compensated", "Use the motion compensated deinterlacing algorithm",
594 594
       0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, .unit = "mode" },
595
+
596
+    { "rate", "Generate output at frame rate or field rate",
597
+      OFFSET(field_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 2, FLAGS, "rate" },
598
+    { "frame", "Output at frame rate (one frame of output for each field-pair)",
599
+      0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "rate" },
600
+    { "field", "Output at field rate (one frame of output for each field)",
601
+      0, AV_OPT_TYPE_CONST, { .i64 = 2 }, .unit = "rate" },
602
+
603
+    { "auto", "Only deinterlace fields, passing frames through unchanged",
604
+      OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
605
+
595 606
     { NULL },
596 607
 };
597 608