1/* 2 * Copyright (c) 2003 Rich Felker 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavutil/avassert.h" 22#include "libavutil/imgutils.h" 23#include "libavutil/opt.h" 24#include "libavutil/pixdesc.h" 25#include "avfilter.h" 26#include "formats.h" 27#include "internal.h" 28#include "video.h" 29#include "vf_pullup.h" 30 31#define F_HAVE_BREAKS 1 32#define F_HAVE_AFFINITY 2 33 34#define BREAK_LEFT 1 35#define BREAK_RIGHT 2 36 37#define OFFSET(x) offsetof(PullupContext, x) 38#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM 39 40static const AVOption pullup_options[] = { 41 { "jl", "set left junk size", OFFSET(junk_left), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, 42 { "jr", "set right junk size", OFFSET(junk_right), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, 43 { "jt", "set top junk size", OFFSET(junk_top), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS }, 44 { "jb", "set bottom junk size", OFFSET(junk_bottom), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS }, 45 { "sb", "set strict breaks", OFFSET(strict_breaks), AV_OPT_TYPE_INT, {.i64=0},-1, 1, FLAGS }, 46 { "mp", "set metric plane", OFFSET(metric_plane), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mp" }, 47 { "y", "luma", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mp" }, 48 { "u", "chroma blue", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mp" }, 49 { "v", "chroma red", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mp" }, 50 { NULL } 51}; 52 53AVFILTER_DEFINE_CLASS(pullup); 54 55static int query_formats(AVFilterContext *ctx) 56{ 57 static const enum AVPixelFormat pix_fmts[] = { 58 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, 59 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, 60 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, 61 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, 62 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, 63 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_GRAY8, 64 AV_PIX_FMT_NONE 65 }; 66 ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); 67 return 0; 68} 69 70#define ABS(a) ((a) > 0 ? (a) : -(a)) 71 72static int diff_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s) 73{ 74 int i, j, diff = 0; 75 76 for (i = 0; i < 4; i++) { 77 for (j = 0; j < 8; j++) 78 diff += ABS(a[j] - b[j]); 79 a += s; 80 b += s; 81 } 82 83 return diff; 84} 85 86static int comb_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s) 87{ 88 int i, j, comb = 0; 89 90 for (i = 0; i < 4; i++) { 91 for (j = 0; j < 8; j++) 92 comb += ABS((a[j] << 1) - b[j - s] - b[j ]) + 93 ABS((b[j] << 1) - a[j ] - a[j + s]); 94 a += s; 95 b += s; 96 } 97 98 return comb; 99} 100 101static int var_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s) 102{ 103 int i, j, var = 0; 104 105 for (i = 0; i < 3; i++) { 106 for (j = 0; j < 8; j++) 107 var += ABS(a[j] - a[j + s]); 108 a += s; 109 } 110 111 return 4 * var; /* match comb scaling */ 112} 113 114static int alloc_metrics(PullupContext *s, PullupField *f) 115{ 116 f->diffs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->diffs)); 117 f->combs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->combs)); 118 f->vars = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->vars)); 119 120 if (!f->diffs || !f->combs || !f->vars) { 121 av_freep(&f->diffs); 122 av_freep(&f->combs); 123 av_freep(&f->vars); 124 return AVERROR(ENOMEM); 125 } 126 return 0; 127} 128 129static void free_field_queue(PullupField *head) 130{ 131 PullupField *f = head; 132 do { 133 PullupField *next; 134 if (!f) 135 break; 136 av_free(f->diffs); 137 av_free(f->combs); 138 av_free(f->vars); 139 next = f->next; 140 memset(f, 0, sizeof(*f)); // clear all pointers to avoid stale ones 141 av_free(f); 142 f = next; 143 } while (f != head); 144} 145 146static PullupField *make_field_queue(PullupContext *s, int len) 147{ 148 PullupField *head, *f; 149 150 f = head = av_mallocz(sizeof(*head)); 151 if (!f) 152 return NULL; 153 154 if (alloc_metrics(s, f) < 0) { 155 av_free(f); 156 return NULL; 157 } 158 159 for (; len > 0; len--) { 160 f->next = av_mallocz(sizeof(*f->next)); 161 if (!f->next) { 162 free_field_queue(head); 163 return NULL; 164 } 165 166 f->next->prev = f; 167 f = f->next; 168 if (alloc_metrics(s, f) < 0) { 169 free_field_queue(head); 170 return NULL; 171 } 172 } 173 174 f->next = head; 175 head->prev = f; 176 177 return head; 178} 179 180static int config_input(AVFilterLink *inlink) 181{ 182 AVFilterContext *ctx = inlink->dst; 183 PullupContext *s = ctx->priv; 184 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); 185 int mp = s->metric_plane; 186 187 s->nb_planes = av_pix_fmt_count_planes(inlink->format); 188 189 if (mp + 1 > s->nb_planes) { 190 av_log(ctx, AV_LOG_ERROR, "input format does not have such plane\n"); 191 return AVERROR(EINVAL); 192 } 193 194 s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); 195 s->planeheight[0] = s->planeheight[3] = inlink->h; 196 s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); 197 s->planewidth[0] = s->planewidth[3] = inlink->w; 198 199 s->metric_w = (s->planewidth[mp] - ((s->junk_left + s->junk_right) << 3)) >> 3; 200 s->metric_h = (s->planeheight[mp] - ((s->junk_top + s->junk_bottom) << 1)) >> 3; 201 s->metric_offset = (s->junk_left << 3) + (s->junk_top << 1) * s->planewidth[mp]; 202 s->metric_length = s->metric_w * s->metric_h; 203 204 av_log(ctx, AV_LOG_DEBUG, "w: %d h: %d\n", s->metric_w, s->metric_h); 205 av_log(ctx, AV_LOG_DEBUG, "offset: %d length: %d\n", s->metric_offset, s->metric_length); 206 207 s->head = make_field_queue(s, 8); 208 if (!s->head) 209 return AVERROR(ENOMEM); 210 211 s->diff = diff_c; 212 s->comb = comb_c; 213 s->var = var_c; 214 215 if (ARCH_X86) 216 ff_pullup_init_x86(s); 217 return 0; 218} 219 220static int config_output(AVFilterLink *outlink) 221{ 222 outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; 223 return 0; 224} 225 226static PullupBuffer *pullup_lock_buffer(PullupBuffer *b, int parity) 227{ 228 if (!b) 229 return NULL; 230 231 if ((parity + 1) & 1) 232 b->lock[0]++; 233 if ((parity + 1) & 2) 234 b->lock[1]++; 235 236 return b; 237} 238 239static void pullup_release_buffer(PullupBuffer *b, int parity) 240{ 241 if (!b) 242 return; 243 244 if ((parity + 1) & 1) 245 b->lock[0]--; 246 if ((parity + 1) & 2) 247 b->lock[1]--; 248} 249 250static int alloc_buffer(PullupContext *s, PullupBuffer *b) 251{ 252 int i; 253 254 if (b->planes[0]) 255 return 0; 256 for (i = 0; i < s->nb_planes; i++) { 257 b->planes[i] = av_malloc(s->planeheight[i] * s->planewidth[i]); 258 } 259 if (s->nb_planes == 1) 260 b->planes[1] = av_malloc(4*256); 261 262 return 0; 263} 264 265static PullupBuffer *pullup_get_buffer(PullupContext *s, int parity) 266{ 267 int i; 268 269 /* Try first to get the sister buffer for the previous field */ 270 if (parity < 2 && s->last && parity != s->last->parity 271 && !s->last->buffer->lock[parity]) { 272 alloc_buffer(s, s->last->buffer); 273 return pullup_lock_buffer(s->last->buffer, parity); 274 } 275 276 /* Prefer a buffer with both fields open */ 277 for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { 278 if (s->buffers[i].lock[0]) 279 continue; 280 if (s->buffers[i].lock[1]) 281 continue; 282 alloc_buffer(s, &s->buffers[i]); 283 return pullup_lock_buffer(&s->buffers[i], parity); 284 } 285 286 if (parity == 2) 287 return 0; 288 289 /* Search for any half-free buffer */ 290 for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { 291 if (((parity + 1) & 1) && s->buffers[i].lock[0]) 292 continue; 293 if (((parity + 1) & 2) && s->buffers[i].lock[1]) 294 continue; 295 alloc_buffer(s, &s->buffers[i]); 296 return pullup_lock_buffer(&s->buffers[i], parity); 297 } 298 299 return NULL; 300} 301 302static int queue_length(PullupField *begin, PullupField *end) 303{ 304 PullupField *f; 305 int count = 1; 306 307 if (!begin || !end) 308 return 0; 309 310 for (f = begin; f != end; f = f->next) 311 count++; 312 313 return count; 314} 315 316static int find_first_break(PullupField *f, int max) 317{ 318 int i; 319 320 for (i = 0; i < max; i++) { 321 if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT) 322 return i + 1; 323 f = f->next; 324 } 325 326 return 0; 327} 328 329static void compute_breaks(PullupContext *s, PullupField *f0) 330{ 331 PullupField *f1 = f0->next; 332 PullupField *f2 = f1->next; 333 PullupField *f3 = f2->next; 334 int i, l, max_l = 0, max_r = 0; 335 336 if (f0->flags & F_HAVE_BREAKS) 337 return; 338 339 f0->flags |= F_HAVE_BREAKS; 340 341 /* Special case when fields are 100% identical */ 342 if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) { 343 f2->breaks |= BREAK_RIGHT; 344 return; 345 } 346 347 if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) { 348 f1->breaks |= BREAK_LEFT; 349 return; 350 } 351 352 for (i = 0; i < s->metric_length; i++) { 353 l = f2->diffs[i] - f3->diffs[i]; 354 355 if ( l > max_l) 356 max_l = l; 357 if (-l > max_r) 358 max_r = -l; 359 } 360 361 /* Don't get tripped up when differences are mostly quant error */ 362 if (max_l + max_r < 128) 363 return; 364 if (max_l > 4 * max_r) 365 f1->breaks |= BREAK_LEFT; 366 if (max_r > 4 * max_l) 367 f2->breaks |= BREAK_RIGHT; 368} 369 370static void compute_affinity(PullupContext *s, PullupField *f) 371{ 372 int i, max_l = 0, max_r = 0, l; 373 374 if (f->flags & F_HAVE_AFFINITY) 375 return; 376 377 f->flags |= F_HAVE_AFFINITY; 378 379 if (f->buffer == f->next->next->buffer) { 380 f->affinity = 1; 381 f->next->affinity = 0; 382 f->next->next->affinity = -1; 383 f->next->flags |= F_HAVE_AFFINITY; 384 f->next->next->flags |= F_HAVE_AFFINITY; 385 return; 386 } 387 388 for (i = 0; i < s->metric_length; i++) { 389 int v = f->vars[i]; 390 int lv = f->prev->vars[i]; 391 int rv = f->next->vars[i]; 392 int lc = f->combs[i] - (v + lv) + ABS(v - lv); 393 int rc = f->next->combs[i] - (v + rv) + ABS(v - rv); 394 395 lc = FFMAX(lc, 0); 396 rc = FFMAX(rc, 0); 397 l = lc - rc; 398 399 if ( l > max_l) 400 max_l = l; 401 if (-l > max_r) 402 max_r = -l; 403 } 404 405 if (max_l + max_r < 64) 406 return; 407 408 if (max_r > 6 * max_l) 409 f->affinity = -1; 410 else if (max_l > 6 * max_r) 411 f->affinity = 1; 412} 413 414static int decide_frame_length(PullupContext *s) 415{ 416 PullupField *f0 = s->first; 417 PullupField *f1 = f0->next; 418 PullupField *f2 = f1->next; 419 PullupField *f; 420 int i, l, n; 421 422 if (queue_length(s->first, s->last) < 4) 423 return 0; 424 425 f = s->first; 426 n = queue_length(f, s->last); 427 for (i = 0; i < n - 1; i++) { 428 if (i < n - 3) 429 compute_breaks(s, f); 430 431 compute_affinity(s, f); 432 433 f = f->next; 434 } 435 436 if (f0->affinity == -1) 437 return 1; 438 439 l = find_first_break(f0, 3); 440 441 if (l == 1 && s->strict_breaks < 0) 442 l = 0; 443 444 switch (l) { 445 case 1: 446 return 1 + (s->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1); 447 case 2: 448 /* FIXME: strictly speaking, f0->prev is no longer valid... :) */ 449 if (s->strict_pairs 450 && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT) 451 && (f0->affinity != 1 || f1->affinity != -1) ) 452 return 1; 453 return 1 + (f1->affinity != 1); 454 case 3: 455 return 2 + (f2->affinity != 1); 456 default: 457 /* 9 possibilities covered before switch */ 458 if (f1->affinity == 1) 459 return 1; /* covers 6 */ 460 else if (f1->affinity == -1) 461 return 2; /* covers 6 */ 462 else if (f2->affinity == -1) { /* covers 2 */ 463 return (f0->affinity == 1) ? 3 : 1; 464 } else { 465 return 2; /* the remaining 6 */ 466 } 467 } 468} 469 470static PullupFrame *pullup_get_frame(PullupContext *s) 471{ 472 PullupFrame *fr = &s->frame; 473 int i, n = decide_frame_length(s); 474 int aff = s->first->next->affinity; 475 476 av_assert1(n < FF_ARRAY_ELEMS(fr->ifields)); 477 if (!n || fr->lock) 478 return NULL; 479 480 fr->lock++; 481 fr->length = n; 482 fr->parity = s->first->parity; 483 fr->buffer = 0; 484 485 for (i = 0; i < n; i++) { 486 /* We cheat and steal the buffer without release+relock */ 487 fr->ifields[i] = s->first->buffer; 488 s->first->buffer = 0; 489 s->first = s->first->next; 490 } 491 492 if (n == 1) { 493 fr->ofields[fr->parity ] = fr->ifields[0]; 494 fr->ofields[fr->parity ^ 1] = 0; 495 } else if (n == 2) { 496 fr->ofields[fr->parity ] = fr->ifields[0]; 497 fr->ofields[fr->parity ^ 1] = fr->ifields[1]; 498 } else if (n == 3) { 499 if (!aff) 500 aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1; 501 fr->ofields[fr->parity ] = fr->ifields[1 + aff]; 502 fr->ofields[fr->parity ^ 1] = fr->ifields[1 ]; 503 } 504 505 pullup_lock_buffer(fr->ofields[0], 0); 506 pullup_lock_buffer(fr->ofields[1], 1); 507 508 if (fr->ofields[0] == fr->ofields[1]) { 509 fr->buffer = fr->ofields[0]; 510 pullup_lock_buffer(fr->buffer, 2); 511 return fr; 512 } 513 514 return fr; 515} 516 517static void pullup_release_frame(PullupFrame *f) 518{ 519 int i; 520 521 for (i = 0; i < f->length; i++) 522 pullup_release_buffer(f->ifields[i], f->parity ^ (i & 1)); 523 524 pullup_release_buffer(f->ofields[0], 0); 525 pullup_release_buffer(f->ofields[1], 1); 526 527 if (f->buffer) 528 pullup_release_buffer(f->buffer, 2); 529 f->lock--; 530} 531 532static void compute_metric(PullupContext *s, int *dest, 533 PullupField *fa, int pa, PullupField *fb, int pb, 534 int (*func)(const uint8_t *, const uint8_t *, ptrdiff_t)) 535{ 536 int mp = s->metric_plane; 537 int xstep = 8; 538 int ystep = s->planewidth[mp] << 3; 539 int stride = s->planewidth[mp] << 1; /* field stride */ 540 int w = s->metric_w * xstep; 541 uint8_t *a, *b; 542 int x, y; 543 544 if (!fa->buffer || !fb->buffer) 545 return; 546 547 /* Shortcut for duplicate fields (e.g. from RFF flag) */ 548 if (fa->buffer == fb->buffer && pa == pb) { 549 memset(dest, 0, s->metric_length * sizeof(*dest)); 550 return; 551 } 552 553 a = fa->buffer->planes[mp] + pa * s->planewidth[mp] + s->metric_offset; 554 b = fb->buffer->planes[mp] + pb * s->planewidth[mp] + s->metric_offset; 555 556 for (y = 0; y < s->metric_h; y++) { 557 for (x = 0; x < w; x += xstep) 558 *dest++ = func(a + x, b + x, stride); 559 a += ystep; b += ystep; 560 } 561} 562 563static int check_field_queue(PullupContext *s) 564{ 565 int ret; 566 567 if (s->head->next == s->first) { 568 PullupField *f = av_mallocz(sizeof(*f)); 569 570 if (!f) 571 return AVERROR(ENOMEM); 572 573 if ((ret = alloc_metrics(s, f)) < 0) { 574 av_free(f); 575 return ret; 576 } 577 578 f->prev = s->head; 579 f->next = s->first; 580 s->head->next = f; 581 s->first->prev = f; 582 } 583 584 return 0; 585} 586 587static void pullup_submit_field(PullupContext *s, PullupBuffer *b, int parity) 588{ 589 PullupField *f; 590 591 /* Grow the circular list if needed */ 592 if (check_field_queue(s) < 0) 593 return; 594 595 /* Cannot have two fields of same parity in a row; drop the new one */ 596 if (s->last && s->last->parity == parity) 597 return; 598 599 f = s->head; 600 f->parity = parity; 601 f->buffer = pullup_lock_buffer(b, parity); 602 f->flags = 0; 603 f->breaks = 0; 604 f->affinity = 0; 605 606 compute_metric(s, f->diffs, f, parity, f->prev->prev, parity, s->diff); 607 compute_metric(s, f->combs, parity ? f->prev : f, 0, parity ? f : f->prev, 1, s->comb); 608 compute_metric(s, f->vars, f, parity, f, -1, s->var); 609 emms_c(); 610 611 /* Advance the circular list */ 612 if (!s->first) 613 s->first = s->head; 614 615 s->last = s->head; 616 s->head = s->head->next; 617} 618 619static void copy_field(PullupContext *s, 620 PullupBuffer *dst, PullupBuffer *src, int parity) 621{ 622 uint8_t *dd, *ss; 623 int i; 624 625 for (i = 0; i < s->nb_planes; i++) { 626 ss = src->planes[i] + parity * s->planewidth[i]; 627 dd = dst->planes[i] + parity * s->planewidth[i]; 628 629 av_image_copy_plane(dd, s->planewidth[i] << 1, 630 ss, s->planewidth[i] << 1, 631 s->planewidth[i], s->planeheight[i] >> 1); 632 } 633} 634 635static void pullup_pack_frame(PullupContext *s, PullupFrame *fr) 636{ 637 int i; 638 639 if (fr->buffer) 640 return; 641 642 if (fr->length < 2) 643 return; /* FIXME: deal with this */ 644 645 for (i = 0; i < 2; i++) { 646 if (fr->ofields[i]->lock[i^1]) 647 continue; 648 649 fr->buffer = fr->ofields[i]; 650 pullup_lock_buffer(fr->buffer, 2); 651 copy_field(s, fr->buffer, fr->ofields[i^1], i^1); 652 return; 653 } 654 655 fr->buffer = pullup_get_buffer(s, 2); 656 657 copy_field(s, fr->buffer, fr->ofields[0], 0); 658 copy_field(s, fr->buffer, fr->ofields[1], 1); 659} 660 661static int filter_frame(AVFilterLink *inlink, AVFrame *in) 662{ 663 AVFilterContext *ctx = inlink->dst; 664 AVFilterLink *outlink = ctx->outputs[0]; 665 PullupContext *s = ctx->priv; 666 PullupBuffer *b; 667 PullupFrame *f; 668 AVFrame *out; 669 int p, ret = 0; 670 671 b = pullup_get_buffer(s, 2); 672 if (!b) { 673 av_log(ctx, AV_LOG_WARNING, "Could not get buffer!\n"); 674 f = pullup_get_frame(s); 675 pullup_release_frame(f); 676 goto end; 677 } 678 679 av_image_copy(b->planes, s->planewidth, 680 (const uint8_t**)in->data, in->linesize, 681 inlink->format, inlink->w, inlink->h); 682 683 p = in->interlaced_frame ? !in->top_field_first : 0; 684 pullup_submit_field(s, b, p ); 685 pullup_submit_field(s, b, p^1); 686 687 if (in->repeat_pict) 688 pullup_submit_field(s, b, p); 689 690 pullup_release_buffer(b, 2); 691 692 f = pullup_get_frame(s); 693 if (!f) 694 goto end; 695 696 if (f->length < 2) { 697 pullup_release_frame(f); 698 f = pullup_get_frame(s); 699 if (!f) 700 goto end; 701 if (f->length < 2) { 702 pullup_release_frame(f); 703 if (!in->repeat_pict) 704 goto end; 705 f = pullup_get_frame(s); 706 if (!f) 707 goto end; 708 if (f->length < 2) { 709 pullup_release_frame(f); 710 goto end; 711 } 712 } 713 } 714 715 /* If the frame isn't already exportable... */ 716 if (!f->buffer) 717 pullup_pack_frame(s, f); 718 719 out = ff_get_video_buffer(outlink, outlink->w, outlink->h); 720 if (!out) { 721 ret = AVERROR(ENOMEM); 722 goto end; 723 } 724 av_frame_copy_props(out, in); 725 726 av_image_copy(out->data, out->linesize, 727 (const uint8_t**)f->buffer->planes, s->planewidth, 728 inlink->format, inlink->w, inlink->h); 729 730 ret = ff_filter_frame(outlink, out); 731 pullup_release_frame(f); 732end: 733 av_frame_free(&in); 734 return ret; 735} 736 737static av_cold void uninit(AVFilterContext *ctx) 738{ 739 PullupContext *s = ctx->priv; 740 int i; 741 742 free_field_queue(s->head); 743 s->last = NULL; 744 745 for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { 746 av_freep(&s->buffers[i].planes[0]); 747 av_freep(&s->buffers[i].planes[1]); 748 av_freep(&s->buffers[i].planes[2]); 749 } 750} 751 752static const AVFilterPad pullup_inputs[] = { 753 { 754 .name = "default", 755 .type = AVMEDIA_TYPE_VIDEO, 756 .filter_frame = filter_frame, 757 .config_props = config_input, 758 }, 759 { NULL } 760}; 761 762static const AVFilterPad pullup_outputs[] = { 763 { 764 .name = "default", 765 .type = AVMEDIA_TYPE_VIDEO, 766 .config_props = config_output, 767 }, 768 { NULL } 769}; 770 771AVFilter ff_vf_pullup = { 772 .name = "pullup", 773 .description = NULL_IF_CONFIG_SMALL("Pullup from field sequence to frames."), 774 .priv_size = sizeof(PullupContext), 775 .priv_class = &pullup_class, 776 .uninit = uninit, 777 .query_formats = query_formats, 778 .inputs = pullup_inputs, 779 .outputs = pullup_outputs, 780}; 781