📄 yuvkineco.c
字号:
/* * Copyright (C) 2001,2002 Kawamata/Hitoshi <hitoshi.kawamata@nifty.ne.jp> * * This program is free software; you can redistribute it and/or modify * 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. * * This program is distributed in the hope that it will be useful, * 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 with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <mpegtimecode.h>#include "yuvfilters.h"#define NOISERATIO(N) (((N)+63)/64*63)#define MAXHALFHEIGHT 288#define NOISEMAX 31#define DEINTLRESO 1000#define DEFAULTDTHR16 4#define DEFAULTNOISE 10#define DEFAULTDEINTL 10static voidbuf_debug(char *buf, FILE *fp, const char *format, ...){ size_t n; va_list ap; va_start(ap, format); vsprintf(buf + strlen(buf), format, ap); va_end(ap); if (buf[(n = strlen(buf) - 1)] == '\n') { if (fp) { fputs(buf, fp); } else {#ifdef MJPEGTOOLS buf[n] = '\0'; mjpeg_debug(buf);#else fputs(buf, stderr);#endif } buf[0] = '\0'; }}typedef struct { YfTaskCore_t _; int fpscode0; FILE *cyfp; int cytype; int nfields; int nframes; int iget; int iuse; int iput; YfFrame_t *frame; int dthr16; int deintl; int nointlmax, deintlmin; unsigned int deintlframes; unsigned int deintldist[100]; union { struct { /* use in 1st try */ unsigned long dist[NOISEMAX+1]; unsigned long total; unsigned int level0, level; } noise; struct { /* use in retry */ char buff[32]; char *p; } cy; } u; struct { unsigned long odiff; /* odd field (or non-intarlaced frame) diff */ unsigned long ediff; /* even field diff (only when interlaced) */ long eoediff; /* previous even - odd - even diff */ unsigned long diffdist[NOISEMAX+1]; } framestat[0];} YfTask_t;DEFINE_STD_YFTASKCLASS(yuvkineco);DECLARE_YFTASKCLASS(yuvycsnoise);static const char *do_usage(void){ return "[-{u|s}] [-F OutputFPSCODE] [-S YCSNoiseThreashold] [-n NoiseLevel] " "[-c CycleSearchThreashold] [-i DeinterlacePixelsPermil] " "{[-C OutputCycleListName] | -[ON] InputCycleListName}";}static YfTaskCore_t *do_init(int argc, char **argv, const YfTaskCore_t *h0){ int fpscode; int nframes, nfields; YfTask_t *h; int c; int cytype = 0; char *cyname = NULL; char *ycsthres = NULL; YfTaskCore_t *hycs = NULL; int dthr16 = DEFAULTDTHR16; int noiselevel = DEFAULTNOISE; int deintlval = DEFAULTDEINTL; int output_interlace = 0; fpscode = h0->fpscode; while ((c = getopt(argc, argv, "usF:S:n:c:i:C:O:N:")) != -1) { switch (c) { case 'u': output_interlace = 1; break; case 's': output_interlace = 2; break; case 'F': fpscode = atoi(optarg); break; case 'S': ycsthres = optarg; break; case 'n': noiselevel = atoi(optarg); break; case 'c': dthr16 = atoi(optarg); break; case 'i': deintlval = atoi(optarg); break; case 'C': case 'O': case 'N': cytype = c; cyname = optarg; break; default: return NULL; } } if (cytype != 'N' && (h0->fpscode < 3 || 5 < h0->fpscode)) { WERROR("unsupported input fps"); return NULL; } if (fpscode < 1 || h0->fpscode < fpscode) { WERROR("illeagal output fpscode"); return NULL; } if (y4m_si_get_interlace(&h0->si) == Y4M_ILACE_BOTTOM_FIRST) { WERROR("unsupported field order"); return NULL; } if (ycsthres) { char ycssopt[] = "-S"; char *ycsargv[] = { argv[0], ycssopt, ycsthres, NULL, }; optind = 1; if (!(hycs = YfAddNewTask(&yuvycsnoise, (sizeof ycsargv / sizeof ycsargv[0]) - 1, ycsargv, h0))) return NULL; } nframes = ((cytype && cytype != 'C')? 2: (h0->fpscode == 3)? 49: 9); nfields = ((y4m_si_get_interlace(&h0->si) == Y4M_UNKNOWN)? (MAXHALFHEIGHT < h0->height): y4m_si_get_interlace(&h0->si)) + 1; if (deintlval < 0 || nfields == 1 || (cytype && cytype != 'C')) deintlval = -1; else if (2 * DEINTLRESO < deintlval) deintlval = 2 * DEINTLRESO; if (dthr16 < 0) dthr16 = 0; else if (32 < dthr16) dthr16 = 32; if (noiselevel < 0) noiselevel = 0; else if (255 < noiselevel) noiselevel = 255; h = (YfTask_t *) YfAllocateTask(&yuvkineco, (sizeof *h + ((((!cytype || cytype == 'C')? (sizeof h->framestat[0]): 0) + FRAMEBYTES(y4m_si_get_chroma(&h0->si), h0->width, h0->height)) * nframes) + ((0 <= deintlval)? FRAMEBYTES(y4m_si_get_chroma(&h0->si), h0->width, h0->height): 0)), (hycs? hycs: h0)); if (!h) return NULL; if (output_interlace == 2 && (y4m_si_get_interlace(&h0->si) != Y4M_ILACE_TOP_FIRST || CHDIV(y4m_si_get_chroma(&h0->si)) != 2)) output_interlace = 3; y4m_si_set_interlace(&h->_.si, ((output_interlace == 1)? Y4M_UNKNOWN: (output_interlace == 2)? Y4M_ILACE_TOP_FIRST: Y4M_ILACE_NONE)); h->_.fpscode = fpscode; h->fpscode0 = h0->fpscode; h->cytype = cytype; h->nfields = nfields; h->nframes = nframes; h->frame = (YfFrame_t *)(h->framestat + (nframes * (!cytype || cytype == 'C'))); h->dthr16 = dthr16; h->deintl = deintlval * DATABYTES(y4m_si_get_chroma(&h0->si), h0->width, h0->height) / (2*DEINTLRESO); h->nointlmax = -1; h->deintlmin = 0x7fffffff; h->u.noise.level0 = h->u.noise.level = noiselevel; if (0 <= h->deintl) nframes++; while (0 <= --nframes) YfInitFrame((YfFrame_t *)((char *)h->frame + (nframes * FRAMEBYTES(y4m_si_get_chroma(&h0->si), h0->width, h0->height))), &h->_); if (!cytype) goto RETURN; if ((h->cyfp = fopen(cyname, ((cytype == 'C')? "w": "r"))) == NULL) { perror(cyname); goto ERROR_RETURN; } if (cytype == 'C') { fprintf(h->cyfp, "# 2-3 pull down cycle list\n""# Generated by 'yuvkineco%s -F%d%s%s -n%d -c%d -i%d -C %s'\n""#\n""# Each character in list mean how each frame processed:\n""# O,o: output\n""# D,d: deinterlaced and output\n""# X,x: bottom field replaced by previous one and output\n""# M,m: bottom field replaced by previous one and deinterlaced and output\n""# _: dropped\n""# Lower case characters mean output but might drop if framerate was lower.\n""#\n""# You can edit this list by hand and retry yuvkineco.\n""# When edit, you can use characters in addition to above:\n""# E,e: always deinterlace\n""# Y,y: always replace bottom field by previous one\n""# N,n: always replace bottom field by previous one and deinterlace\n""# T,t: duplicate top field\n""# B,b: duplicate bottom field\n""# Upper case characters mean always output.\n""# Lower case characters mean output or drop according to framerate.\n""#\n""# Use this list with old input to generator yuvkineco,\n""# do 'yuvkineco -F fpscode -O %s',\n""# with output new,\n""# do 'yuvkineco -F fpscode -N %s'.\n""#\n""# When used as '-O %s':\n""# O,o: output\n""# D,d,E,e: deinterlace and output\n""# X,x,Y,y: replace bottom field by previous one and output\n""# M,m,N,n: replace bottom field by previous one and deinterlace and output\n""# T,t: duplicate top field and output\n""# B,b: duplicate bottom field and output\n""# _: drop\n""#\n""# When used as '-N %s':\n""# O,o,X,x,D,d,M,m: output\n""# E,e: deinterlace and output\n""# Y,y: replace bottom field by previous one and output\n""# N,n: replace bottom field by previous one and deinterlace and output\n""# T,t: duplicate top field and output\n""# B,b: duplicate bottom field and output\n""# _: ignore\n""#\n""SIZE:%dx%d OLD_FPS:%d NEW_FPS:%d # DON'T CHANGE THIS LINE!!!", ((output_interlace == 1)? " -u": (2 <= output_interlace)? " -s": ""), fpscode, (ycsthres? " -S": ""), (ycsthres? ycsthres: ""), noiselevel, dthr16, deintlval, cyname, cyname, cyname, cyname, cyname, h0->width, h0->height, h0->fpscode, fpscode); } else { int width, height, oldfps, newfps; char buff[128]; h->u.cy.p = h->u.cy.buff; buff[sizeof buff - 1] = buff[sizeof buff - 2] = '\0'; while (fgets(buff, sizeof buff, h->cyfp)) { if (sscanf(buff, "SIZE:%dx%d OLD_FPS:%d NEW_FPS:%d ", &width, &height, &oldfps, &newfps) == 4) { if (width != h0->width || height != h0->height || ((h->cytype == 'O')? oldfps: newfps) != h0->fpscode) { WERROR("input and cycle list not match."); goto ERROR; } if (h->cytype == 'O' && newfps < fpscode) { WERROR("output fpscode greater than specified at 1st try."); goto ERROR; } goto RETURN; } } WERROR("broken cycle list."); ERROR: fclose(h->cyfp); goto ERROR_RETURN; } RETURN: return (YfTaskCore_t *)h; ERROR_RETURN: if (0 <= h->deintl) h->nframes++; while (0 <= --h->nframes) YfFiniFrame((YfFrame_t *)((char *)h->frame + (h->nframes * FRAMEBYTES(y4m_si_get_chroma(&h0->si), h0->width, h0->height)))); YfFreeTask((YfTaskCore_t *)h); return NULL;}static voiddumpnoise(YfTask_t *h, FILE *fp){ int i; char buf[256]; if (!h->u.noise.total) return; buf[0] = '\0'; buf_debug(buf, fp, "#\n"); buf_debug(buf, fp, "# noise level: %u (# of sample: %lu); noise distribution:\n", h->u.noise.level, h->u.noise.total); buf_debug(buf, fp, "#"); for (i = 0; i <= NOISEMAX; i++) buf_debug(buf, fp, " %lu", (unsigned long)((((uint64_t)h->u.noise.dist[i] * 1000) + h->u.noise.total - 1) / h->u.noise.total)); buf_debug(buf, fp, "\n"); if (0 <= h->deintl) { int bytes = DATABYTES(y4m_si_get_chroma(&h->_.si), h->_.width, h->_.height); buf_debug(buf, fp, "# deinterlaced frames: %u; pixels/frame distribution:", h->deintlframes); for (i = 0; i < sizeof h->deintldist / sizeof h->deintldist[0]; i++) { if (!(i % 10)) { buf_debug(buf, fp, "\n"); buf_debug(buf, fp, "# %3d:", i); } buf_debug(buf, fp, "%7u", h->deintldist[i]); } buf_debug(buf, fp, "\n"); buf_debug(buf, fp, "# maximum permil of non-interlaced frames: %3d\n", h->nointlmax * (2 * DEINTLRESO) / bytes); buf_debug(buf, fp, "# minimum permil of deinterlaced frames: %3d\n", ((h->deintlmin == 0x7fffffff)? -1: (h->deintlmin * (2 * DEINTLRESO) / bytes))); }}static voiddo_fini(YfTaskCore_t *handle){ YfTask_t *h = (YfTask_t *)handle; while (h->iuse < h->iget) do_frame((YfTaskCore_t *)h, NULL, NULL); if (1 < verbose) dumpnoise(h, NULL); if (h->cytype == 'C') { putc('\n', h->cyfp); dumpnoise(h, h->cyfp); fclose(h->cyfp); } if (0 <= h->deintl) h->nframes++; while (0 <= --h->nframes) YfFiniFrame((YfFrame_t *)((char *)h->frame + (h->nframes * FRAMEBYTES(y4m_si_get_chroma(&h->_.si), h->_.width, h->_.height)))); YfFreeTask((YfTaskCore_t *)h);}static voidputcy(YfTask_t *h, int c){ MPEG_timecode_t tc; int f; f = mpeg_timecode(&tc, h->iuse, h->fpscode0, 0.); if (f <= 0) { putc('\n', h->cyfp); if (tc.s == 0) { if (tc.m % 10 == 0) dumpnoise(h, h->cyfp); fputs("#\n""# OLD NEW 0.... 5.... 10....15.... 20....25....\n", h->cyfp); } fprintf(h->cyfp, "%06d/%02d:%02d:%02d:%02d ", h->iuse, tc.h, tc.m, tc.s, tc.f); mpeg_timecode(&tc, h->iput, h->_.fpscode, 0.); fprintf(h->cyfp, "%06d/%02d:%02d:%02d:%02d", h->iput, tc.h, tc.m, tc.s, tc.f); } if (f < 0) { int i; f = -f; for (i = -1; i <= f; i++) putc(' ', h->cyfp); } if (f % 10 == 0) putc(' ', h->cyfp); if (f % 5 == 0) putc(' ', h->cyfp); if (c != '_' && h->framestat[h->iuse % h->nframes].eoediff == -9999999) c += 'X' - 'O'; putc(c, h->cyfp);}static intdeinterlace(YfTask_t *h, unsigned char *data, int width, int height, int noise){ int pln, i, j, n = 0; for (pln = 0; pln < 3; pln++) { for (i = 1; i < height - 1; i += 2) { for (j = 0; j < width; j++) { int ymin = data[((i - 1) * width) + j]; int ynow = data[((i ) * width) + j]; int ymax = data[((i + 1) * width) + j]; int ynxt = data[((i + 2) * width) + j]; if (ymax < ymin) { int ytmp = ymax; ymax = ymin; ymin = ytmp; } ymin -= noise; ymax += noise; if ((ynow < ymin && ynxt < ymin ) || (ymax < ynow && ymax < ynxt )) n++; else if (!(ynow < ymin || ymax < ynow)) continue;#if 0 if (i < height - 3) { int ynx2 = data[((i + 3) * width) + j]; if ((ynx2 < ynxt && ynxt < ymin) || (ymax < ynxt && ynxt < ynx2)) continue; }#endif ynow = (ymin + ymax) / 2; data[((i ) * width) + j] = ynow; if (i < height - 3) {#if 0 int ynx2 = data[((i + 4) * width) + j]; if ((ynx2 < ymin && ynxt < ymin) || (ymax < ynx2 && ymax < ynxt))#endif continue; } data[((i + 2) * width) + j] = ynow;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -