vf_yadif.c 15.2 KB
Newer Older
1 2
/*
 * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at>
James Darnley's avatar
James Darnley committed
3
 *               2010      James Darnley <james.darnley@gmail.com>
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or modify
8 9 10 11
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
18
 * with Libav; if not, write to the Free Software Foundation, Inc.,
19 20 21 22 23
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "libavutil/cpu.h"
#include "libavutil/common.h"
24
#include "libavutil/pixdesc.h"
25
#include "avfilter.h"
26
#include "formats.h"
27
#include "internal.h"
28
#include "video.h"
29 30 31 32 33
#include "yadif.h"

#undef NDEBUG
#include <assert.h>

Luca Barbato's avatar
Luca Barbato committed
34 35
#define PERM_RWP AV_PERM_WRITE | AV_PERM_PRESERVE | AV_PERM_REUSE

36
#define CHECK(j)\
37
    {   int score = FFABS(cur[mrefs + off_left + (j)] - cur[prefs + off_left - (j)])\
38
                  + FFABS(cur[mrefs  +(j)] - cur[prefs  -(j)])\
39
                  + FFABS(cur[mrefs + off_right + (j)] - cur[prefs + off_right - (j)]);\
40 41
        if (score < spatial_score) {\
            spatial_score= score;\
42
            spatial_pred= (cur[mrefs  +(j)] + cur[prefs  -(j)])>>1;\
43

44 45
#define FILTER(start, end) \
    for (x = start;  x < end; x++) { \
James Darnley's avatar
James Darnley committed
46 47 48 49 50 51
        int c = cur[mrefs]; \
        int d = (prev2[0] + next2[0])>>1; \
        int e = cur[prefs]; \
        int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
        int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \
        int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \
Luca Barbato's avatar
Luca Barbato committed
52 53
        int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
        int spatial_pred = (c+e) >> 1; \
54 55 56 57
        int off_right = (x < w - 1) ? 1 : -1;\
        int off_left  = x ? -1 : 1;\
        int spatial_score = FFABS(cur[mrefs + off_left]  - cur[prefs + off_left]) + FFABS(c-e) \
                          + FFABS(cur[mrefs + off_right] - cur[prefs + off_right]) - 1; \
James Darnley's avatar
James Darnley committed
58
 \
59 60 61 62
        if (x > 2 && x < w - 3) {\
            CHECK(-1) CHECK(-2) }} }} \
            CHECK( 1) CHECK( 2) }} }} \
        }\
James Darnley's avatar
James Darnley committed
63 64
 \
        if (mode < 2) { \
Luca Barbato's avatar
Luca Barbato committed
65 66 67 68
            int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
            int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
            int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
            int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
James Darnley's avatar
James Darnley committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
 \
            diff = FFMAX3(diff, min, -max); \
        } \
 \
        if (spatial_pred > d + diff) \
           spatial_pred = d + diff; \
        else if (spatial_pred < d - diff) \
           spatial_pred = d - diff; \
 \
        dst[0] = spatial_pred; \
 \
        dst++; \
        cur++; \
        prev++; \
        next++; \
        prev2++; \
        next2++; \
    }
87

Anton Khirnov's avatar
Anton Khirnov committed
88 89
static void filter_line_c(void *dst1,
                          void *prev1, void *cur1, void *next1,
James Darnley's avatar
James Darnley committed
90 91
                          int w, int prefs, int mrefs, int parity, int mode)
{
Anton Khirnov's avatar
Anton Khirnov committed
92 93 94 95
    uint8_t *dst  = dst1;
    uint8_t *prev = prev1;
    uint8_t *cur  = cur1;
    uint8_t *next = next1;
James Darnley's avatar
James Darnley committed
96 97 98
    int x;
    uint8_t *prev2 = parity ? prev : cur ;
    uint8_t *next2 = parity ? cur  : next;
99

100
    FILTER(0, w)
James Darnley's avatar
James Darnley committed
101
}
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1,
                         int w, int prefs, int mrefs, int parity, int mode,
                         int l_edge)
{
    uint8_t *dst  = dst1;
    uint8_t *prev = prev1;
    uint8_t *cur  = cur1;
    uint8_t *next = next1;
    int x;
    uint8_t *prev2 = parity ? prev : cur ;
    uint8_t *next2 = parity ? cur  : next;

    FILTER(0, l_edge)

    dst  = (uint8_t*)dst1  + w - 3;
    prev = (uint8_t*)prev1 + w - 3;
    cur  = (uint8_t*)cur1  + w - 3;
    next = (uint8_t*)next1 + w - 3;
    prev2 = (uint8_t*)(parity ? prev : cur);
    next2 = (uint8_t*)(parity ? cur  : next);

    FILTER(w - 3, w)
}


Anton Khirnov's avatar
Anton Khirnov committed
128 129
static void filter_line_c_16bit(void *dst1,
                                void *prev1, void *cur1, void *next1,
Luca Barbato's avatar
Luca Barbato committed
130 131
                                int w, int prefs, int mrefs, int parity,
                                int mode)
James Darnley's avatar
James Darnley committed
132
{
Anton Khirnov's avatar
Anton Khirnov committed
133 134 135 136
    uint16_t *dst  = dst1;
    uint16_t *prev = prev1;
    uint16_t *cur  = cur1;
    uint16_t *next = next1;
James Darnley's avatar
James Darnley committed
137 138 139 140 141
    int x;
    uint16_t *prev2 = parity ? prev : cur ;
    uint16_t *next2 = parity ? cur  : next;
    mrefs /= 2;
    prefs /= 2;
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
    FILTER(0, w)
}

static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1,
                               int w, int prefs, int mrefs, int parity, int mode,
                               int l_edge)
{
    uint16_t *dst  = dst1;
    uint16_t *prev = prev1;
    uint16_t *cur  = cur1;
    uint16_t *next = next1;
    int x;
    uint16_t *prev2 = parity ? prev : cur ;
    uint16_t *next2 = parity ? cur  : next;

    FILTER(0, l_edge)

    dst   = (uint16_t*)dst1  + w - 3;
    prev  = (uint16_t*)prev1 + w - 3;
    cur   = (uint16_t*)cur1  + w - 3;
    next  = (uint16_t*)next1 + w - 3;
    prev2 = (uint16_t*)(parity ? prev : cur);
    next2 = (uint16_t*)(parity ? cur  : next);

    FILTER(w - 3, w)
168 169 170 171 172 173 174 175
}

static void filter(AVFilterContext *ctx, AVFilterBufferRef *dstpic,
                   int parity, int tff)
{
    YADIFContext *yadif = ctx->priv;
    int y, i;

176 177 178
    for (i = 0; i < yadif->csp->nb_components; i++) {
        int w = dstpic->video->w;
        int h = dstpic->video->h;
179
        int refs = yadif->cur->linesize[i];
Luca Barbato's avatar
Luca Barbato committed
180
        int df = (yadif->csp->comp[i].depth_minus1 + 8) / 8;
181
        int l_edge, l_edge_pix;
182

183
        if (i == 1 || i == 2) {
184 185 186 187 188
        /* Why is this not part of the per-plane description thing? */
            w >>= yadif->csp->log2_chroma_w;
            h >>= yadif->csp->log2_chroma_h;
        }

189 190 191 192 193 194
        /* filtering reads 3 pixels to the left/right; to avoid invalid reads,
         * we need to call the c variant which avoids this for border pixels
         */
        l_edge     = yadif->req_align;
        l_edge_pix = l_edge / df;

195 196
        for (y = 0; y < h; y++) {
            if ((y ^ parity) & 1) {
Luca Barbato's avatar
Luca Barbato committed
197 198 199 200 201
                uint8_t *prev = &yadif->prev->data[i][y * refs];
                uint8_t *cur  = &yadif->cur ->data[i][y * refs];
                uint8_t *next = &yadif->next->data[i][y * refs];
                uint8_t *dst  = &dstpic->data[i][y * dstpic->linesize[i]];
                int     mode  = y == 1 || y + 2 == h ? 2 : yadif->mode;
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
                if (yadif->req_align) {
                    yadif->filter_line(dst + l_edge, prev + l_edge, cur + l_edge,
                                       next + l_edge, w - l_edge_pix - 3,
                                       y + 1 < h ? refs : -refs,
                                       y ? -refs : refs,
                                       parity ^ tff, mode);
                    yadif->filter_edges(dst, prev, cur, next, w,
                                         y + 1 < h ? refs : -refs,
                                         y ? -refs : refs,
                                         parity ^ tff, mode, l_edge_pix);
                } else {
                    yadif->filter_line(dst, prev, cur, next + l_edge, w,
                                       y + 1 < h ? refs : -refs,
                                       y ? -refs : refs,
                                       parity ^ tff, mode);
                }
218
            } else {
Luca Barbato's avatar
Luca Barbato committed
219 220
                memcpy(&dstpic->data[i][y * dstpic->linesize[i]],
                       &yadif->cur->data[i][y * refs], w * df);
221 222 223
            }
        }
    }
224 225

    emms_c();
226 227
}

Luca Barbato's avatar
Luca Barbato committed
228 229
static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
                                           int w, int h)
230 231
{
    AVFilterBufferRef *picref;
Luca Barbato's avatar
Luca Barbato committed
232 233
    int width  = FFALIGN(w, 32);
    int height = FFALIGN(h + 2, 32);
234 235
    int i;

236
    picref = ff_default_get_video_buffer(link, perms, width, height);
237 238 239 240 241

    picref->video->w = w;
    picref->video->h = h;

    for (i = 0; i < 3; i++)
242
        picref->data[i] += picref->linesize[i];
243 244 245 246

    return picref;
}

247
static int return_frame(AVFilterContext *ctx, int is_second)
Stefano Sabatini's avatar
Stefano Sabatini committed
248
{
249
    YADIFContext *yadif = ctx->priv;
Luca Barbato's avatar
Luca Barbato committed
250
    AVFilterLink *link  = ctx->outputs[0];
251
    int tff, ret;
252 253 254

    if (yadif->parity == -1) {
        tff = yadif->cur->video->interlaced ?
Luca Barbato's avatar
Luca Barbato committed
255
              yadif->cur->video->top_field_first : 1;
256
    } else {
Luca Barbato's avatar
Luca Barbato committed
257
        tff = yadif->parity ^ 1;
258
    }
259

260
    if (is_second) {
Luca Barbato's avatar
Luca Barbato committed
261
        yadif->out = ff_get_video_buffer(link, PERM_RWP, link->w, link->h);
262 263 264
        if (!yadif->out)
            return AVERROR(ENOMEM);

265 266 267
        avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
        yadif->out->video->interlaced = 0;
    }
268 269 270

    filter(ctx, yadif->out, tff ^ !is_second, tff);

271
    if (is_second) {
Robert Nagy's avatar
Robert Nagy committed
272 273 274 275 276
        int64_t cur_pts  = yadif->cur->pts;
        int64_t next_pts = yadif->next->pts;

        if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
            yadif->out->pts = cur_pts + next_pts;
277 278 279 280
        } else {
            yadif->out->pts = AV_NOPTS_VALUE;
        }
    }
281
    ret = ff_filter_frame(ctx->outputs[0], yadif->out);
282

Stefano Sabatini's avatar
Stefano Sabatini committed
283
    yadif->frame_pending = (yadif->mode&1) && !is_second;
284
    return ret;
285 286
}

287
static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
288 289 290 291
{
    AVFilterContext *ctx = link->dst;
    YADIFContext *yadif = ctx->priv;

Stefano Sabatini's avatar
Stefano Sabatini committed
292
    if (yadif->frame_pending)
293 294 295 296 297 298 299 300
        return_frame(ctx, 1);

    if (yadif->prev)
        avfilter_unref_buffer(yadif->prev);
    yadif->prev = yadif->cur;
    yadif->cur  = yadif->next;
    yadif->next = picref;

Stefano Sabatini's avatar
Stefano Sabatini committed
301
    if (!yadif->cur)
302
        return 0;
303

304 305
    if (yadif->auto_enable && !yadif->cur->video->interlaced) {
        yadif->out  = avfilter_ref_buffer(yadif->cur, AV_PERM_READ);
306 307 308
        if (!yadif->out)
            return AVERROR(ENOMEM);

309
        avfilter_unref_bufferp(&yadif->prev);
Robert Nagy's avatar
Robert Nagy committed
310 311
        if (yadif->out->pts != AV_NOPTS_VALUE)
            yadif->out->pts *= 2;
312
        return ff_filter_frame(ctx->outputs[0], yadif->out);
313 314
    }

315 316 317
    if (!yadif->prev &&
        !(yadif->prev = avfilter_ref_buffer(yadif->cur, AV_PERM_READ)))
        return AVERROR(ENOMEM);
318

Luca Barbato's avatar
Luca Barbato committed
319 320
    yadif->out = ff_get_video_buffer(ctx->outputs[0], PERM_RWP,
                                     link->w, link->h);
321 322
    if (!yadif->out)
        return AVERROR(ENOMEM);
323

324 325
    avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
    yadif->out->video->interlaced = 0;
Luca Barbato's avatar
Luca Barbato committed
326

Robert Nagy's avatar
Robert Nagy committed
327 328
    if (yadif->out->pts != AV_NOPTS_VALUE)
        yadif->out->pts *= 2;
Luca Barbato's avatar
Luca Barbato committed
329

330
    return return_frame(ctx, 0);
331 332 333 334 335 336 337
}

static int request_frame(AVFilterLink *link)
{
    AVFilterContext *ctx = link->src;
    YADIFContext *yadif = ctx->priv;

Stefano Sabatini's avatar
Stefano Sabatini committed
338
    if (yadif->frame_pending) {
339 340 341 342
        return_frame(ctx, 1);
        return 0;
    }

Stefano Sabatini's avatar
Stefano Sabatini committed
343
    do {
344 345
        int ret;

Robert Nagy's avatar
Robert Nagy committed
346 347 348
        if (yadif->eof)
            return AVERROR_EOF;

349
        ret  = ff_request_frame(link->src->inputs[0]);
Robert Nagy's avatar
Robert Nagy committed
350 351

        if (ret == AVERROR_EOF && yadif->next) {
Luca Barbato's avatar
Luca Barbato committed
352 353 354
            AVFilterBufferRef *next =
                avfilter_ref_buffer(yadif->next, AV_PERM_READ);

355 356 357
            if (!next)
                return AVERROR(ENOMEM);

Robert Nagy's avatar
Robert Nagy committed
358 359
            next->pts = yadif->next->pts * 2 - yadif->cur->pts;

360
            filter_frame(link->src->inputs[0], next);
Robert Nagy's avatar
Robert Nagy committed
361 362
            yadif->eof = 1;
        } else if (ret < 0) {
363
            return ret;
Robert Nagy's avatar
Robert Nagy committed
364
        }
Stefano Sabatini's avatar
Stefano Sabatini committed
365
    } while (!yadif->cur);
366 367 368 369 370 371 372 373 374

    return 0;
}

static int poll_frame(AVFilterLink *link)
{
    YADIFContext *yadif = link->src->priv;
    int ret, val;

Stefano Sabatini's avatar
Stefano Sabatini committed
375
    if (yadif->frame_pending)
376 377
        return 1;

378
    val = ff_poll_frame(link->src->inputs[0]);
379 380
    if (val <= 0)
        return val;
381

Luca Barbato's avatar
Luca Barbato committed
382 383
    //FIXME change API to not requre this red tape
    if (val == 1 && !yadif->next) {
384
        if ((ret = ff_request_frame(link->src->inputs[0])) < 0)
385
            return ret;
386
        val = ff_poll_frame(link->src->inputs[0]);
387 388
        if (val <= 0)
            return val;
389
    }
390
    assert(yadif->next || !val);
391

392 393 394
    if (yadif->auto_enable && yadif->next && !yadif->next->video->interlaced)
        return val;

395 396 397 398 399 400 401
    return val * ((yadif->mode&1)+1);
}

static av_cold void uninit(AVFilterContext *ctx)
{
    YADIFContext *yadif = ctx->priv;

402 403 404
    if (yadif->prev) avfilter_unref_bufferp(&yadif->prev);
    if (yadif->cur ) avfilter_unref_bufferp(&yadif->cur );
    if (yadif->next) avfilter_unref_bufferp(&yadif->next);
405 406 407 408
}

static int query_formats(AVFilterContext *ctx)
{
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
    static const enum AVPixelFormat pix_fmts[] = {
        AV_PIX_FMT_YUV420P,
        AV_PIX_FMT_YUV422P,
        AV_PIX_FMT_YUV444P,
        AV_PIX_FMT_YUV410P,
        AV_PIX_FMT_YUV411P,
        AV_PIX_FMT_GRAY8,
        AV_PIX_FMT_YUVJ420P,
        AV_PIX_FMT_YUVJ422P,
        AV_PIX_FMT_YUVJ444P,
        AV_NE( AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE ),
        AV_PIX_FMT_YUV440P,
        AV_PIX_FMT_YUVJ440P,
        AV_NE( AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUV420P10LE ),
        AV_NE( AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUV422P10LE ),
        AV_NE( AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUV444P10LE ),
        AV_NE( AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUV420P16LE ),
        AV_NE( AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUV422P16LE ),
        AV_NE( AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUV444P16LE ),
        AV_PIX_FMT_YUVA420P,
        AV_PIX_FMT_NONE
430 431
    };

432
    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
433 434 435 436

    return 0;
}

437
static av_cold int init(AVFilterContext *ctx, const char *args)
438 439 440 441 442
{
    YADIFContext *yadif = ctx->priv;

    yadif->mode = 0;
    yadif->parity = -1;
443
    yadif->auto_enable = 0;
444

Luca Barbato's avatar
Luca Barbato committed
445 446 447
    if (args)
        sscanf(args, "%d:%d:%d",
               &yadif->mode, &yadif->parity, &yadif->auto_enable);
448

Luca Barbato's avatar
Luca Barbato committed
449 450
    av_log(ctx, AV_LOG_VERBOSE, "mode:%d parity:%d auto_enable:%d\n",
           yadif->mode, yadif->parity, yadif->auto_enable);
451 452 453 454

    return 0;
}

Robert Nagy's avatar
Robert Nagy committed
455 456
static int config_props(AVFilterLink *link)
{
457 458
    YADIFContext *s = link->src->priv;

Robert Nagy's avatar
Robert Nagy committed
459 460 461 462 463
    link->time_base.num = link->src->inputs[0]->time_base.num;
    link->time_base.den = link->src->inputs[0]->time_base.den * 2;
    link->w             = link->src->inputs[0]->w;
    link->h             = link->src->inputs[0]->h;

464 465
    s->csp = av_pix_fmt_desc_get(link->format);
    if (s->csp->comp[0].depth_minus1 / 8 == 1) {
466 467
        s->filter_line  = filter_line_c_16bit;
        s->filter_edges = filter_edges_16bit;
468
    } else {
469 470
        s->filter_line  = filter_line_c;
        s->filter_edges = filter_edges;
471 472 473 474 475

        if (ARCH_X86)
            ff_yadif_init_x86(s);
    }

Robert Nagy's avatar
Robert Nagy committed
476 477 478
    return 0;
}

479 480 481 482 483
static const AVFilterPad avfilter_vf_yadif_inputs[] = {
    {
        .name             = "default",
        .type             = AVMEDIA_TYPE_VIDEO,
        .get_video_buffer = get_video_buffer,
484
        .filter_frame     = filter_frame,
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    },
    { NULL }
};

static const AVFilterPad avfilter_vf_yadif_outputs[] = {
    {
        .name          = "default",
        .type          = AVMEDIA_TYPE_VIDEO,
        .poll_frame    = poll_frame,
        .request_frame = request_frame,
        .config_props  = config_props,
    },
    { NULL }
};

500 501 502 503 504 505 506 507 508
AVFilter avfilter_vf_yadif = {
    .name          = "yadif",
    .description   = NULL_IF_CONFIG_SMALL("Deinterlace the input image"),

    .priv_size     = sizeof(YADIFContext),
    .init          = init,
    .uninit        = uninit,
    .query_formats = query_formats,

509 510 511
    .inputs    = avfilter_vf_yadif_inputs,

    .outputs   = avfilter_vf_yadif_outputs,
512
};