📄 deintl.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
////////////////////////////////////////////////////////
// defines
////////////////////////////////////////////////////////
// Defineing TIME_DEINTERLACE will time the deinterlacer
// and write a file with filename TIME_DEINTERLACE_FILENAME
// with the times.
//#define TIME_DEINTERLACE
//#define TIME_DEINTERLACE_FILENAME "d:\\dintl.log"
////////////////////////////////////////////////////////
// include files
////////////////////////////////////////////////////////
#include "hlxclib/stdlib.h"
#include "hlxclib/string.h"
#define INTL_I420_CODE
#ifdef TIME_DEINTERLACE
#include "hlxclib/stdio.h"
#endif
#include "mmx_util.h"
#include "deintl.h"
////////////////////////////////////////////////////////
// internal prototypes
////////////////////////////////////////////////////////
static void
Deinterlace_RGB24(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_I420(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_RGB24_Fast(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_I420_Fast(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_I420_Advanced(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_I420_EdgeInterp(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
static void
Deinterlace_RGB24_Field(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format, int field);
static void
Deinterlace_I420_Field(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format, int field);
static void
Deinterlace_I420_FlipFlop(unsigned char *frame, unsigned char *temp_frame, int pels, int lines, int pitch, int format);
#ifdef _M_IX86
static void
Deinterlace_I420_MMX(unsigned char *frame, unsigned char *prev_frame, int pels, int lines, int pitch, int format);
#endif
int
C_DetectInterlace_I420(unsigned char *frame, unsigned char *prev_frame, int first_frame, int pels, int lines, int pitch);
////////////////////////////////////////////////////////
// macros
////////////////////////////////////////////////////////
#define MEDIAN_3(a,b,c) \
((a > b)? \
( \
(b > c)? \
(b): \
( \
(a > c)? \
(c): \
(a) \
) \
): \
( \
(a > c)? \
(a): \
( \
(b > c)? \
(c): \
(b) \
) \
)) \
#define MABS(v) (tmp=(v),((tmp)^(tmp>>31)))
#define ABS(a) (((a) < 0) ? (-(a)) : (a))
#define DIFF_FCN(v) ((v)*(v)) // Squared difference
static const int SQUARED_TAB[255+255+1] = {
65025, 64516, 64009, 63504, 63001, 62500,
62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, 57600,
57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900,
52441, 51984, 51529, 51076, 50625, 50176, 49729, 49284, 48841, 48400,
47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100,
43681, 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000,
39601, 39204, 38809, 38416, 38025, 37636, 37249, 36864, 36481, 36100,
35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400,
32041, 31684, 31329, 30976, 30625, 30276, 29929, 29584, 29241, 28900,
28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, 25600,
25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500,
22201, 21904, 21609, 21316, 21025, 20736, 20449, 20164, 19881, 19600,
19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900,
16641, 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400,
14161, 13924, 13689, 13456, 13225, 12996, 12769, 12544, 12321, 12100,
11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000,
9801, 9604, 9409, 9216, 9025, 8836, 8649, 8464, 8281, 8100,
7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, 6400,
6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900,
4761, 4624, 4489, 4356, 4225, 4096, 3969, 3844, 3721, 3600,
3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500,
2401, 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600,
1521, 1444, 1369, 1296, 1225, 1156, 1089, 1024, 961, 900,
841, 784, 729, 676, 625, 576, 529, 484, 441, 400,
361, 324, 289, 256, 225, 196, 169, 144, 121, 100,
81, 64, 49, 36, 25, 16, 9, 4, 1, 0,
1, 4, 9, 16, 25, 36, 49, 64, 81, 100,
121, 144, 169, 196, 225, 256, 289, 324, 361, 400,
441, 484, 529, 576, 625, 676, 729, 784, 841, 900,
961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600,
1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500,
2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600,
3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900,
5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400,
6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100,
8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000,
10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100,
12321, 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400,
14641, 14884, 15129, 15376, 15625, 15876, 16129, 16384, 16641, 16900,
17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600,
19881, 20164, 20449, 20736, 21025, 21316, 21609, 21904, 22201, 22500,
22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, 25600,
25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900,
29241, 29584, 29929, 30276, 30625, 30976, 31329, 31684, 32041, 32400,
32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100,
36481, 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000,
40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264, 43681, 44100,
44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400,
48841, 49284, 49729, 50176, 50625, 51076, 51529, 51984, 52441, 52900,
53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, 57600,
58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500,
63001, 63504, 64009, 64516, 65025
};
#define MSQUARED(v) (SQUARED_TAB[(v) + 255])
// Some thresholds
#define INTL_DIFF_THRESH 40000
#define INTL_HORIZ_THRESH 80
#ifdef TIME_DEINTERLACE
static unsigned int num_avg = 0;
static unsigned int num_med = 0;
#endif
int
InitDeinterlace (
int pels, int lines, int pitch,
int format,
INTL_MODE mode,
T_DEINTL_STATE **state)
{
T_DEINTL_STATE *new_state = 0;
if (*state == 0)
{
new_state = (T_DEINTL_STATE *)malloc(sizeof(T_DEINTL_STATE));
}
if (new_state == 0)
return 1;
new_state->pels = pels;
new_state->lines = lines;
new_state->pitch = pitch;
new_state->format = format;
new_state->detection_measure = (lines > 242)?(16):(0);
new_state->commit_deinterlace = FALSE;
*state = new_state;
return 0;
}
void
FreeDeinterlace (T_DEINTL_STATE **state)
{
if (*state != 0)
free(*state);
*state = 0;
}
BOOL
IsContentInterlaced (T_DEINTL_STATE *state)
{
if (state != 0)
return (state->commit_deinterlace == 1)?(TRUE):(FALSE);
return FALSE;
}
void
ResetDeinterlace (T_DEINTL_STATE *state)
{
state->detection_measure = 0;
state->commit_deinterlace = FALSE;
}
////////////////////////////////////////////////////////
//
// Deinterlace
//
// Top level function to deinterlace a video frame
//
// Parameters:
// frame: Pointer to the frame to deinterlace
// prev_frame: Pointer to the previous frame.
// Better results are achieved by giving
// the previous *interlaced* frame
// pels,
// lines,
// pitch: Frame dimensions
// format: INTL_FORMAT_RGB24 or INTL_FORMAT_I420
// mode: Choose either using both fields or
// to remove one field entirely
// (see 'deintl.h')
//
////////////////////////////////////////////////////////
int
Deinterlace(
unsigned char *frame,
unsigned char *prev_frame,
int pels, int lines, int pitch,
int format,
int first_frame,
INTL_MODE mode,
T_DEINTL_STATE *state)
{
if (pels == 0)
pels = state->pels;
if (lines == 0)
lines = state->lines;
if (pitch == 0)
pitch = state->pitch;
if (format == 0)
format = state->format;
unsigned char *pfp = (first_frame == TRUE)?(NULL):(prev_frame);
// Unless were going to do detection first (i.e. in INTL_MODE_SMART_AUTO mode),
// don't de-interlace when there is less than 242 lines. This is a little
// check to prevent unintentional de-interlacing of probable progressive frames.
if (lines < 242 && mode != INTL_MODE_SMART_AUTO)
return 0;
// Run detection
if (mode == INTL_MODE_SMART_AUTO)
{
unsigned char *detection_frame;
unsigned char *detection_prev_frame;
int res;
if (format == INTL_FORMAT_I420)
{
// point to the Y-Plane
detection_frame = frame;
detection_prev_frame = prev_frame;
}
if (format == INTL_FORMAT_RGB24)
{
// point to the G-Plane
detection_frame = frame + pels * lines;
detection_prev_frame = prev_frame + pels * lines;
}
// Perform detection
res = C_DetectInterlace_I420(
detection_frame,
detection_prev_frame,
first_frame,
pels, lines, pitch);
// Update the "detection measure" based on result of detection
switch (res)
{
case INTL_STRONG_INTERLACE:
{
state->detection_measure = (31 * state->detection_measure + 256) >> 5;
}
break;
case INTL_WEAK_INTERLACE:
{
state->detection_measure = (31 * state->detection_measure + 256) >> 5;
}
break;
case INTL_WEAK_PROGRESSIVE:
{
state->detection_measure = (31 * state->detection_measure + 0) >> 5;
}
break;
case INTL_STRONG_PROGRESSIVE:
{
state->detection_measure = 0;
}
break;
}
// If the detection measure is above a threshold, set this flag used
// to indicate we are confident the content is interlaced.
if (state->detection_measure > 128)
{
state->commit_deinterlace = TRUE;
}
// If the detection measure is above this threshold, we should
// de-interlace this frame. Otherwise, return without de-interlacing
if (state->detection_measure > 16)
{
mode = INTL_MODE_SMART;
}
else
{
return 0;
}
}
#ifdef TIME_DEINTERLACE
FILE *fp = NULL;
double proc_time;
USE_CODEC_TIMER;
num_avg = 0;
num_med = 0;
START_CODEC_TIMER;
#endif
switch (format)
{
#ifdef INTL_RBG24_CODE
case INTL_FORMAT_RGB24:
Deinterlace_RGB24_Fast(frame, pfp, pels, lines, pitch, format);
break;
#endif
#ifdef INTL_I420_CODE
case INTL_FORMAT_I420:
#ifdef USE_MMX_DEINTERLACING //_M_IX86
if (checkMmxAvailablity() & CPU_HAS_MMX)
Deinterlace_I420_MMX(frame, pfp, pels, lines, pitch, format);
else
#endif
// Neelesh's new deinterlacer.
Deinterlace_I420_Advanced(frame, pfp, pels, lines, pitch, format);
break;
#endif
}
#ifdef TIME_DEINTERLACE
STOP_CODEC_TIMER(proc_time);
fp = fopen(TIME_DEINTERLACE_FILENAME,"a+");
if (fp != NULL)
{
fprintf(fp,"deinterlace time\t%f\t%d\t%d\n",proc_time,num_avg,num_med);
fclose(fp);
}
#endif
return 1;
}
////////////////////////////////////////////////////////
//
// C_DetectInterlace_I420
//
// Top level function to detect the presense of
// interlaced video content
//
// Parameters:
// frame: Pointer to the frame to deinterlace
// prev_frame: Pointer to the previous frame.
// pels,
// lines,
// pitch: Frame dimensions
//
////////////////////////////////////////////////////////
// Threshold: If 8x8 SAD is above MOVEMENT_THRESH then
// we'll decide that the block is in motion
#define MOVEMENT_THRESH (400)
// This is the factor by which 8x8 are skipped (not checked).
// SKIP_FACTOR = 1 means no skipping.
#define SKIP_FACTOR 4
#ifdef DEBUG
// This increments with each call,
// and is useful for debugging a specific frame.
static unsigned int call_count = 0;
#endif
int
C_DetectInterlace_I420(
unsigned char *frame,
unsigned char *prev_frame,
int first_frame,
int pels, int lines, int pitch)
{
unsigned int image_size = (unsigned int)(pels * lines);
// pre-calculated image size used for determining thresholds
unsigned int interlaced_blocks = 0;
// count of the number of 8x8 blocks that look to be interlaced
unsigned int progressive_blocks = 0;
// count of the number of 8x8 blocks that look to be progressive
unsigned int step1v_tot = 0;
// running total of the 1-step squared vertical difference of pixels
unsigned int step2v_tot = 0;
// running total of the 2-step squared vertical difference of pixels
unsigned int step1h_tot = 0;
// running total of the 1-step squared horizontal difference of pixels
unsigned int step2h_tot = 0;
// running total of the 2-step squared horizontal difference of pixels
unsigned char *fp, *pp;
unsigned char *f0, *f1, *f2, *f3;
// various temporary frame pointers
int i, j, k; // loop counter
int tmp; // intermediate values for correlation and SAD macro
int d0, d1; // SAD counters
#ifdef DEBUG
call_count++;
#endif
// We have no detection scheme for the first frame yet.
if (first_frame)
{
return INTL_NO_DETECTION;
}
// Loop through tiled 8x8 blocks of the image
for (i = 8; i < lines - 8; i += 8)
{
// Start pointer at new line
fp = frame + i * pitch + (i & (8*(SKIP_FACTOR - 1))) + 8;
pp = prev_frame + i * pitch + (i & (8*(SKIP_FACTOR - 1))) + 8;
for (j = 8; j < pels - 8; j += 8 * SKIP_FACTOR)
{
f0 = fp;
f1 = f0 + pitch;
f2 = pp;
f3 = f2 + pitch;
d0 = d1 = 0;
// Calculate SAD for even and odd lines of 8x8 block.
// We're doing a partial SAD here for speed.
for (k = 0; k < 4; k++)
{
d0 += MABS(f0[0] - f2[0]);
d0 += MABS(f0[2] - f2[2]);
d0 += MABS(f0[4] - f2[4]);
d0 += MABS(f0[6] - f2[6]);
d1 += MABS(f1[1] - f3[1]);
d1 += MABS(f1[3] - f3[3]);
d1 += MABS(f1[5] - f3[5]);
d1 += MABS(f1[7] - f3[7]);
f0 += 2 * pitch;
f1 += 2 * pitch;
f2 += 2 * pitch;
f3 += 2 * pitch;
}
d0 <<= 1;
d1 <<= 1;
// If there is enough difference to determine movement,
// check this region for indications of interlaced artifacts
if (d0 > MOVEMENT_THRESH || d1 > MOVEMENT_THRESH)
{
int step1v_corr = 0;
int step2v_corr = 0;
int step1h_corr = 0;
int step2h_corr = 0;
f0 = fp;
f1 = f0 + pitch;
f2 = f1 + pitch;
// Determine 1 and 2 step pixel differences for 8x8 region
for (k = 0; k < 4; k++)
{
tmp = f0[1] - f1[1];
step1v_corr += MSQUARED(tmp);
tmp = f0[1] - f2[1];
step2v_corr += MSQUARED(tmp);
tmp = f1[0] - f1[1];
step1h_corr += MSQUARED(tmp);
tmp = f1[0] - f1[2];
step2h_corr += MSQUARED(tmp);
tmp = f0[3] - f1[3];
step1v_corr += MSQUARED(tmp);
tmp = f0[3] - f2[3];
step2v_corr += MSQUARED(tmp);
tmp = f1[2] - f1[3];
step1h_corr += MSQUARED(tmp);
tmp = f1[2] - f1[4];
step2h_corr += MSQUARED(tmp);
tmp = f0[5] - f1[5];
step1v_corr += MSQUARED(tmp);
tmp = f0[5] - f2[5];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -