📄 tvtime.c
字号:
/** * Copyright (c) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>. * * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <math.h>#if HAVE_INTTYPES_H#include <inttypes.h>#else#include <stdint.h>#endif#include "speedy.h"#include "deinterlace.h"#include "pulldown.h"#include "tvtime.h"/** * This is how many frames to wait until deciding if the pulldown phase * has changed or if we've really found a pulldown sequence. This is * currently set to about 1 second, that is, we won't go into film mode * until we've seen a pulldown sequence successfully for 1 second. */#define PULLDOWN_ERROR_WAIT 60/** * This is how many predictions have to be incorrect before we fall back to * video mode. Right now, if we mess up, we jump to video mode immediately. */#define PULLDOWN_ERROR_THRESHOLD 2/** * Explination of the loop: * * We want to build frames so that they look like this: * Top field: Bot field: * Copy Double * Interp Copy * Copy Interp * Interp Copy * Copy -- * -- -- * -- -- * Copy Interp * Interp Copy * Copy Interp * Double Copy * * So, say a frame is n high. * For the bottom field, the first scanline is blank (special case). * For the top field, the final scanline is blank (special case). * For the rest of the scanlines, we alternate between Copy then Interpolate. * * To do the loop, I go 'Interp then Copy', and handle the first copy * outside the loop for both top and bottom. * The top field therefore handles n-2 scanlines in the loop. * The bot field handles n-2 scanlines in the loop. * * What we pass to the deinterlacing routines: * * Each deinterlacing routine can require data from up to four fields. * The current field is being output is Field 4: * * | Field 3 | Field 2 | Field 1 | Field 0 | * | | T2 | | T0 | * | M3 | | M1 | | * | | B2 | | B0 | * | NX3 | | NX1 | | * * So, since we currently get frames not individual fields from V4L, there * are two possibilities for where these come from: * * CASE 1: Deinterlacing the top field: * | Field 4 | Field 3 | Field 2 | Field 1 | Field 0 | * | T4 | | T2 | | T0 | * | | M3 | | M1 | | * | B4 | | B2 | | B0 | * [-- secondlast --] [-- lastframe --] [-- curframe --] * * CASE 2: Deinterlacing the bottom field: * | Field 4 | Field 3 | Field 2 | Field 1 | Field 0 | * | T4 | | T2 | | T0 | * | | M3 | | M1 | | * | B4 | | B2 | | B0 | * ndlast --] [-- lastframe --] [-- curframe --] * * So, in case 1, we need the previous 2 frames as well as the current * frame, and in case 2, we only need the previous frame, since the * current frame contains both Field 3 and Field 4. */static void pulldown_merge_fields( uint8_t *output, uint8_t *topfield, uint8_t *botfield, int width, int frame_height, int fieldstride, int outstride ){ int i; for( i = 0; i < frame_height; i++ ) { uint8_t *curoutput = output + (i * outstride); if( i & 1 ) { blit_packed422_scanline( curoutput, botfield + ((i / 2) * fieldstride), width ); } else { blit_packed422_scanline( curoutput, topfield + ((i / 2) * fieldstride), width ); } }}static void calculate_pulldown_score_vektor( tvtime_t *tvtime, uint8_t *curframe, uint8_t *lastframe, int instride, int frame_height, int width ){ int i; tvtime->last_topdiff = 0; tvtime->last_botdiff = 0; for( i = 0; i < frame_height; i++ ) { if( i > 40 && (i & 3) == 0 && i < frame_height - 40 ) { tvtime->last_topdiff += diff_factor_packed422_scanline( curframe + (i*instride), lastframe + (i*instride), width ); tvtime->last_botdiff += diff_factor_packed422_scanline( curframe + (i*instride) + instride, lastframe + (i*instride) + instride, width ); } }}int tvtime_build_deinterlaced_frame( tvtime_t *tvtime, uint8_t *output, uint8_t *curframe, uint8_t *lastframe, uint8_t *secondlastframe, int bottom_field, int second_field, int width, int frame_height, int instride, int outstride ){ int i; if( tvtime->pulldown_alg != PULLDOWN_VEKTOR ) { /* If we leave vektor pulldown mode, lose our state. */ tvtime->filmmode = 0; } if( tvtime->pulldown_alg == PULLDOWN_VEKTOR ) { /* Make pulldown phase decisions every top field. */ if( !bottom_field ) { int predicted; predicted = tvtime->pdoffset << 1; if( predicted > PULLDOWN_SEQ_DD ) predicted = PULLDOWN_SEQ_AA; calculate_pulldown_score_vektor( tvtime, curframe, lastframe, instride, frame_height, width ); tvtime->pdoffset = determine_pulldown_offset_short_history_new( tvtime->last_topdiff, tvtime->last_botdiff, 1, predicted ); /* 3:2 pulldown state machine. */ if( !tvtime->pdoffset ) { /* No pulldown offset applies, drop out of pulldown immediately. */ tvtime->pdlastbusted = 0; tvtime->pderror = PULLDOWN_ERROR_WAIT; } else if( tvtime->pdoffset != predicted ) { if( tvtime->pdlastbusted ) { tvtime->pdlastbusted--; tvtime->pdoffset = predicted; } else { tvtime->pderror = PULLDOWN_ERROR_WAIT; } } else { if( tvtime->pderror ) { tvtime->pderror--; } if( !tvtime->pderror ) { tvtime->pdlastbusted = PULLDOWN_ERROR_THRESHOLD; } } if( !tvtime->pderror ) { /* We're in pulldown, reverse it. */ if( !tvtime->filmmode ) { printf( "Film mode enabled.\n" ); tvtime->filmmode = 1; } if( pulldown_drop( tvtime->pdoffset, 0 ) ) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -