...
|
...
|
@@ -294,26 +294,24 @@ static int config_output(AVFilterLink *outlink)
|
294
|
294
|
// ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)) is a faster version of: 255 * (x + y)
|
295
|
295
|
#define UNPREMULTIPLY_ALPHA(x, y) ((((x) << 16) - ((x) << 9) + (x)) / ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)))
|
296
|
296
|
|
297
|
|
-static void blend_slice(AVFilterContext *ctx,
|
|
297
|
+/**
|
|
298
|
+ * Blend image in src to destination buffer dst at position (x, y).
|
|
299
|
+ *
|
|
300
|
+ * It is assumed that the src image at position (x, y) is contained in
|
|
301
|
+ * dst.
|
|
302
|
+ */
|
|
303
|
+static void blend_image(AVFilterContext *ctx,
|
298
|
304
|
AVFilterBufferRef *dst, AVFilterBufferRef *src,
|
299
|
|
- int x, int y, int w, int h,
|
300
|
|
- int slice_y, int slice_w, int slice_h)
|
|
305
|
+ int x, int y)
|
301
|
306
|
{
|
302
|
307
|
OverlayContext *over = ctx->priv;
|
303
|
308
|
int i, j, k;
|
304
|
|
- int width, height;
|
305
|
|
- int overlay_end_y = y+h;
|
306
|
|
- int slice_end_y = slice_y+slice_h;
|
307
|
|
- int end_y, start_y;
|
308
|
|
-
|
309
|
|
- width = FFMIN(slice_w - x, w);
|
310
|
|
- end_y = FFMIN(slice_end_y, overlay_end_y);
|
311
|
|
- start_y = FFMAX(y, slice_y);
|
312
|
|
- height = end_y - start_y;
|
|
309
|
+ int width = src->video->w;
|
|
310
|
+ int height = src->video->h;
|
313
|
311
|
|
314
|
312
|
if (over->main_is_packed_rgb) {
|
315
|
313
|
uint8_t *dp = dst->data[0] + x * over->main_pix_step[0] +
|
316
|
|
- start_y * dst->linesize[0];
|
|
314
|
+ y * dst->linesize[0];
|
317
|
315
|
uint8_t *sp = src->data[0];
|
318
|
316
|
uint8_t alpha; ///< the amount of overlay to blend on to main
|
319
|
317
|
const int dr = over->main_rgba_map[R];
|
...
|
...
|
@@ -327,8 +325,6 @@ static void blend_slice(AVFilterContext *ctx,
|
327
|
327
|
const int sa = over->overlay_rgba_map[A];
|
328
|
328
|
const int sstep = over->overlay_pix_step[0];
|
329
|
329
|
const int main_has_alpha = over->main_has_alpha;
|
330
|
|
- if (slice_y > y)
|
331
|
|
- sp += (slice_y - y) * src->linesize[0];
|
332
|
330
|
for (i = 0; i < height; i++) {
|
333
|
331
|
uint8_t *d = dp, *s = sp;
|
334
|
332
|
for (j = 0; j < width; j++) {
|
...
|
...
|
@@ -378,11 +374,9 @@ static void blend_slice(AVFilterContext *ctx,
|
378
|
378
|
const int main_has_alpha = over->main_has_alpha;
|
379
|
379
|
if (main_has_alpha) {
|
380
|
380
|
uint8_t *da = dst->data[3] + x * over->main_pix_step[3] +
|
381
|
|
- start_y * dst->linesize[3];
|
|
381
|
+ y * dst->linesize[3];
|
382
|
382
|
uint8_t *sa = src->data[3];
|
383
|
383
|
uint8_t alpha; ///< the amount of overlay to blend on to main
|
384
|
|
- if (slice_y > y)
|
385
|
|
- sa += (slice_y - y) * src->linesize[3];
|
386
|
384
|
for (i = 0; i < height; i++) {
|
387
|
385
|
uint8_t *d = da, *s = sa;
|
388
|
386
|
for (j = 0; j < width; j++) {
|
...
|
...
|
@@ -412,15 +406,11 @@ static void blend_slice(AVFilterContext *ctx,
|
412
|
412
|
int hsub = i ? over->hsub : 0;
|
413
|
413
|
int vsub = i ? over->vsub : 0;
|
414
|
414
|
uint8_t *dp = dst->data[i] + (x >> hsub) +
|
415
|
|
- (start_y >> vsub) * dst->linesize[i];
|
|
415
|
+ (y >> vsub) * dst->linesize[i];
|
416
|
416
|
uint8_t *sp = src->data[i];
|
417
|
417
|
uint8_t *ap = src->data[3];
|
418
|
418
|
int wp = FFALIGN(width, 1<<hsub) >> hsub;
|
419
|
419
|
int hp = FFALIGN(height, 1<<vsub) >> vsub;
|
420
|
|
- if (slice_y > y) {
|
421
|
|
- sp += ((slice_y - y) >> vsub) * src->linesize[i];
|
422
|
|
- ap += (slice_y - y) * src->linesize[3];
|
423
|
|
- }
|
424
|
420
|
for (j = 0; j < hp; j++) {
|
425
|
421
|
uint8_t *d = dp, *s = sp, *a = ap;
|
426
|
422
|
for (k = 0; k < wp; k++) {
|
...
|
...
|
@@ -468,11 +458,11 @@ static void blend_slice(AVFilterContext *ctx,
|
468
|
468
|
}
|
469
|
469
|
}
|
470
|
470
|
|
471
|
|
-static int try_start_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
|
|
471
|
+static int try_filter_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
|
472
|
472
|
{
|
473
|
473
|
OverlayContext *over = ctx->priv;
|
474
|
474
|
AVFilterLink *outlink = ctx->outputs[0];
|
475
|
|
- AVFilterBufferRef *next_overpic, *outpicref;
|
|
475
|
+ AVFilterBufferRef *next_overpic;
|
476
|
476
|
int ret;
|
477
|
477
|
|
478
|
478
|
/* Discard obsolete overlay frames: if there is a next overlay frame with pts
|
...
|
...
|
@@ -496,21 +486,21 @@ static int try_start_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
|
496
|
496
|
|
497
|
497
|
/* At this point, we know that the current overlay frame extends to the
|
498
|
498
|
* time of the main frame. */
|
499
|
|
- outlink->out_buf = outpicref = avfilter_ref_buffer(mainpic, ~0);
|
500
|
|
-
|
501
|
499
|
av_dlog(ctx, "main_pts:%s main_pts_time:%s",
|
502
|
|
- av_ts2str(outpicref->pts), av_ts2timestr(outpicref->pts, &outlink->time_base));
|
|
500
|
+ av_ts2str(mainpic->pts), av_ts2timestr(mainpic->pts, &outlink->time_base));
|
503
|
501
|
if (over->overpicref)
|
504
|
502
|
av_dlog(ctx, " over_pts:%s over_pts_time:%s",
|
505
|
503
|
av_ts2str(over->overpicref->pts), av_ts2timestr(over->overpicref->pts, &outlink->time_base));
|
506
|
504
|
av_dlog(ctx, "\n");
|
507
|
505
|
|
508
|
|
- ret = ff_start_frame(ctx->outputs[0], avfilter_ref_buffer(outpicref, ~0));
|
|
506
|
+ if (over->overpicref)
|
|
507
|
+ blend_image(ctx, mainpic, over->overpicref, over->x, over->y);
|
|
508
|
+ ret = ff_filter_frame(ctx->outputs[0], mainpic);
|
509
|
509
|
over->frame_requested = 0;
|
510
|
510
|
return ret;
|
511
|
511
|
}
|
512
|
512
|
|
513
|
|
-static int try_start_next_frame(AVFilterContext *ctx)
|
|
513
|
+static int try_filter_next_frame(AVFilterContext *ctx)
|
514
|
514
|
{
|
515
|
515
|
OverlayContext *over = ctx->priv;
|
516
|
516
|
AVFilterBufferRef *next_mainpic = ff_bufqueue_peek(&over->queue_main, 0);
|
...
|
...
|
@@ -518,41 +508,21 @@ static int try_start_next_frame(AVFilterContext *ctx)
|
518
|
518
|
|
519
|
519
|
if (!next_mainpic)
|
520
|
520
|
return AVERROR(EAGAIN);
|
521
|
|
- if ((ret = try_start_frame(ctx, next_mainpic)) == AVERROR(EAGAIN))
|
|
521
|
+ if ((ret = try_filter_frame(ctx, next_mainpic)) == AVERROR(EAGAIN))
|
522
|
522
|
return ret;
|
523
|
|
- avfilter_unref_buffer(ff_bufqueue_get(&over->queue_main));
|
|
523
|
+ ff_bufqueue_get(&over->queue_main);
|
524
|
524
|
return ret;
|
525
|
525
|
}
|
526
|
526
|
|
527
|
|
-static int try_push_frame(AVFilterContext *ctx)
|
528
|
|
-{
|
529
|
|
- OverlayContext *over = ctx->priv;
|
530
|
|
- AVFilterLink *outlink = ctx->outputs[0];
|
531
|
|
- AVFilterBufferRef *outpicref;
|
532
|
|
- int ret;
|
533
|
|
-
|
534
|
|
- if ((ret = try_start_next_frame(ctx)) < 0)
|
535
|
|
- return ret;
|
536
|
|
- outpicref = outlink->out_buf;
|
537
|
|
- if (over->overpicref)
|
538
|
|
- blend_slice(ctx, outpicref, over->overpicref, over->x, over->y,
|
539
|
|
- over->overpicref->video->w, over->overpicref->video->h,
|
540
|
|
- 0, outpicref->video->w, outpicref->video->h);
|
541
|
|
- if ((ret = ff_draw_slice(outlink, 0, outpicref->video->h, +1)) < 0 ||
|
542
|
|
- (ret = ff_end_frame(outlink)) < 0)
|
543
|
|
- return ret;
|
544
|
|
- return 0;
|
545
|
|
-}
|
546
|
|
-
|
547
|
527
|
static int flush_frames(AVFilterContext *ctx)
|
548
|
528
|
{
|
549
|
529
|
int ret;
|
550
|
530
|
|
551
|
|
- while (!(ret = try_push_frame(ctx)));
|
|
531
|
+ while (!(ret = try_filter_next_frame(ctx)));
|
552
|
532
|
return ret == AVERROR(EAGAIN) ? 0 : ret;
|
553
|
533
|
}
|
554
|
534
|
|
555
|
|
-static int start_frame_main(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
|
|
535
|
+static int filter_frame_main(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
|
556
|
536
|
{
|
557
|
537
|
AVFilterContext *ctx = inlink->dst;
|
558
|
538
|
OverlayContext *over = ctx->priv;
|
...
|
...
|
@@ -560,64 +530,29 @@ static int start_frame_main(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
|
560
|
560
|
|
561
|
561
|
if ((ret = flush_frames(ctx)) < 0)
|
562
|
562
|
return ret;
|
563
|
|
- if ((ret = try_start_frame(ctx, inpicref)) < 0) {
|
|
563
|
+ if ((ret = try_filter_frame(ctx, inpicref)) < 0) {
|
564
|
564
|
if (ret != AVERROR(EAGAIN))
|
565
|
565
|
return ret;
|
566
|
566
|
ff_bufqueue_add(ctx, &over->queue_main, inpicref);
|
567
|
|
- av_assert1(inpicref == inlink->cur_buf);
|
568
|
|
- inlink->cur_buf = NULL;
|
569
|
567
|
}
|
570
|
|
- return 0;
|
571
|
|
-}
|
572
|
568
|
|
573
|
|
-static int draw_slice_main(AVFilterLink *inlink, int y, int h, int slice_dir)
|
574
|
|
-{
|
575
|
|
- AVFilterContext *ctx = inlink->dst;
|
576
|
|
- OverlayContext *over = ctx->priv;
|
577
|
|
- AVFilterLink *outlink = ctx->outputs[0];
|
578
|
|
- AVFilterBufferRef *outpicref = outlink->out_buf;
|
579
|
|
-
|
580
|
|
- if (!outpicref)
|
|
569
|
+ if (!over->overpicref)
|
581
|
570
|
return 0;
|
582
|
|
- if (over->overpicref &&
|
583
|
|
- y + h > over->y && y < over->y + over->overpicref->video->h) {
|
584
|
|
- blend_slice(ctx, outpicref, over->overpicref, over->x, over->y,
|
585
|
|
- over->overpicref->video->w, over->overpicref->video->h,
|
586
|
|
- y, outpicref->video->w, h);
|
587
|
|
- }
|
588
|
|
- return ff_draw_slice(outlink, y, h, slice_dir);
|
589
|
|
-}
|
590
|
|
-
|
591
|
|
-static int end_frame_main(AVFilterLink *inlink)
|
592
|
|
-{
|
593
|
|
- AVFilterContext *ctx = inlink->dst;
|
594
|
|
- AVFilterLink *outlink = ctx->outputs[0];
|
595
|
|
- AVFilterBufferRef *outpicref = outlink->out_buf;
|
596
|
571
|
flush_frames(ctx);
|
597
|
572
|
|
598
|
|
- if (!outpicref)
|
599
|
|
- return 0;
|
600
|
|
- return ff_end_frame(ctx->outputs[0]);
|
601
|
|
-}
|
602
|
|
-
|
603
|
|
-static int start_frame_over(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
|
604
|
|
-{
|
605
|
573
|
return 0;
|
606
|
574
|
}
|
607
|
575
|
|
608
|
|
-static int end_frame_over(AVFilterLink *inlink)
|
|
576
|
+static int filter_frame_over(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
|
609
|
577
|
{
|
610
|
578
|
AVFilterContext *ctx = inlink->dst;
|
611
|
579
|
OverlayContext *over = ctx->priv;
|
612
|
|
- AVFilterBufferRef *inpicref = inlink->cur_buf;
|
613
|
580
|
int ret;
|
614
|
581
|
|
615
|
|
- inlink->cur_buf = NULL;
|
616
|
|
-
|
617
|
582
|
if ((ret = flush_frames(ctx)) < 0)
|
618
|
583
|
return ret;
|
619
|
584
|
ff_bufqueue_add(ctx, &over->queue_over, inpicref);
|
620
|
|
- ret = try_push_frame(ctx);
|
|
585
|
+ ret = try_filter_next_frame(ctx);
|
621
|
586
|
return ret == AVERROR(EAGAIN) ? 0 : ret;
|
622
|
587
|
}
|
623
|
588
|
|
...
|
...
|
@@ -627,7 +562,7 @@ static int request_frame(AVFilterLink *outlink)
|
627
|
627
|
OverlayContext *over = ctx->priv;
|
628
|
628
|
int input, ret;
|
629
|
629
|
|
630
|
|
- if (!try_push_frame(ctx))
|
|
630
|
+ if (!try_filter_next_frame(ctx))
|
631
|
631
|
return 0;
|
632
|
632
|
over->frame_requested = 1;
|
633
|
633
|
while (over->frame_requested) {
|
...
|
...
|
@@ -639,7 +574,7 @@ static int request_frame(AVFilterLink *outlink)
|
639
|
639
|
/* EOF on main is reported immediately */
|
640
|
640
|
if (ret == AVERROR_EOF && input == OVERLAY) {
|
641
|
641
|
over->overlay_eof = 1;
|
642
|
|
- if ((ret = try_start_next_frame(ctx)) != AVERROR(EAGAIN))
|
|
642
|
+ if ((ret = try_filter_next_frame(ctx)) != AVERROR(EAGAIN))
|
643
|
643
|
return ret;
|
644
|
644
|
ret = 0; /* continue requesting frames on main */
|
645
|
645
|
}
|
...
|
...
|
@@ -649,29 +584,20 @@ static int request_frame(AVFilterLink *outlink)
|
649
|
649
|
return 0;
|
650
|
650
|
}
|
651
|
651
|
|
652
|
|
-static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
|
653
|
|
-{
|
654
|
|
- return 0;
|
655
|
|
-}
|
656
|
|
-
|
657
|
652
|
static const AVFilterPad avfilter_vf_overlay_inputs[] = {
|
658
|
653
|
{
|
659
|
654
|
.name = "main",
|
660
|
655
|
.type = AVMEDIA_TYPE_VIDEO,
|
661
|
656
|
.get_video_buffer = ff_null_get_video_buffer,
|
662
|
657
|
.config_props = config_input_main,
|
663
|
|
- .start_frame = start_frame_main,
|
664
|
|
- .draw_slice = draw_slice_main,
|
665
|
|
- .end_frame = end_frame_main,
|
|
658
|
+ .filter_frame = filter_frame_main,
|
666
|
659
|
.min_perms = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE,
|
667
|
660
|
},
|
668
|
661
|
{
|
669
|
662
|
.name = "overlay",
|
670
|
663
|
.type = AVMEDIA_TYPE_VIDEO,
|
671
|
664
|
.config_props = config_input_overlay,
|
672
|
|
- .start_frame = start_frame_over,
|
673
|
|
- .draw_slice = null_draw_slice,
|
674
|
|
- .end_frame = end_frame_over,
|
|
665
|
+ .filter_frame = filter_frame_over,
|
675
|
666
|
.min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
|
676
|
667
|
},
|
677
|
668
|
{ NULL }
|