Windows2003-3790/enduser/netmeeting/av/codecs/dec/dech263/mres.c
2020-09-30 16:53:55 +02:00

631 lines
20 KiB
C

/* File: sv_h263_mres.c */
/*****************************************************************************
** Copyright (c) Digital Equipment Corporation, 1995, 1997 **
** **
** All Rights Reserved. Unpublished rights reserved under the copyright **
** laws of the United States. **
** **
** The software contained on this media is proprietary to and embodies **
** the confidential technology of Digital Equipment Corporation. **
** Possession, use, duplication or dissemination of the software and **
** media is authorized only pursuant to a valid written license from **
** Digital Equipment Corporation. **
** **
** RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. **
** Government is subject to restrictions as set forth in Subparagraph **
** (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. **
******************************************************************************/
#include "sv_h263.h"
#include "proto.h"
static void hfilt121(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols) ;
static void hfilt5(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols) ;
static void vfilt121(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols) ;
static void vfilt5(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols) ;
static void lowpass(unsigned char *img, unsigned char *lp,
int rows, int cols, int ntaps) ;
static void reduce(unsigned char *img, unsigned char *red,
int rows, int cols, int ntaps) ;
static void hpad(unsigned char *img, unsigned char *zp,
unsigned char s,
int rows, int cols, char mode) ;
static void Expand(unsigned char *img, unsigned char *exp,
int rows, int cols, char mode, int ntaps) ;
static void gaussp(unsigned char *img, unsigned char **pyr,
int depth, int rows, int cols, int ntaps) ;
static unsigned char **palloc(int depth, int rows, int cols) ;
static H263_PictImage **PictPyr(H263_PictImage *img, int depth, int rows,
int cols, int ntaps);
static void expyr(unsigned char **pyr, unsigned char **filtd,
int depth, int rows, int cols,
char mode, int ntaps);
static H263_PictImage **GaussFilt(H263_PictImage *img, int depth, int rows,
int cols, int ntaps);
/******************************************************************
* Function hfilt121
* Filters img horizontally with a 1:2:1 filter, subsampling by s.
* rows, cols are the dimensions of img
*****************************************************************/
static void hfilt121(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols)
{
unsigned char *pimg, *pf;
float conv, tmp;
int i, j;
pf = filtd;
pimg = img;
for(i=0; i<rows; i++) {
/* Do first pixel */
conv = (float)gain * ((float)*pimg * (float)2.0 + (float)*(pimg+1) * (float)2.0) / (float)4.0;
tmp = (conv > 255 ? 255 : conv);
*(pf++) = (unsigned char) (tmp < 0 ? 0 : tmp);
pimg+=s;
/* Do line */
for(j=s; j<cols-1; j+=s, pimg+=s) {
conv = (float) gain * ((float)*(pimg-1) + (float)*pimg * (float)2 + (float)*(pimg+1)) / (float)4.0;
tmp = (conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
/* Do last pixel if s equals one */
if(s==1) {
conv = (float)gain * ((float)*pimg * (float)2.0 + (float)*(pimg-1) * (float)2.0) / (float)4.0;
tmp = (conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
pimg+=s;
}
}
}
/******************************************************************
* Function hfilt5
* Filters img horizontally with a 5 tap gaussian filter, subsampling by s.
* rows, cols are the dimensions of img
*****************************************************************/
static void hfilt5(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols)
{
unsigned char *pimg, *pf;
float conv, tmp;
int i, j;
pf = filtd;
pimg = img;
for(i=0; i<rows; i++) {
/* Do line */
for(j=0; j<cols; j+=s, pimg+=s) {
if (j==0)
conv = (float)gain * ((float)6.0 * (float)*pimg + (float)8.0 * (float)*(pimg+1) + (float)2.0 * *(pimg+2)) / (float)16.0;
else if(j==1)
conv = (float)gain * ((float)4.0 * (float)*(pimg-1) + (float)6.0 * (float)*pimg + (float)4.0 * (float)*(pimg+1) + (float)2.0 * (float)*(pimg+2)) / (float)16.0;
else if (j==cols-2)
conv = (float)gain * ((float)2.0 * (float)*(pimg-2) + (float)4.0 * (float)*(pimg-1) + (float)6.0 * (float)*pimg + (float)4.0 * (float)*(pimg+1)) / (float)16.0;
else if (j==cols-1)
conv = (float)gain * ((float)2.0 * (float)*(pimg-2) + (float)8.0 * (float)*(pimg-1) + (float)6.0 * (float)*pimg) / (float)16.0;
else
conv = (float)gain * ((float)*(pimg-2) + (float)4.0 * (float)*(pimg-1) + (float)6.0 * (float)*pimg + (float)4.0 * (float)*(pimg+1) + (float)*(pimg+2)) / (float)16.0;
tmp = (float)(conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
}
}
/******************************************************************
* Function vfilt121
* Filters img vertically with a 1:2:1 filter, subsampling by s.
* rows, cols are the dimensions of img
*****************************************************************/
static void vfilt121(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols)
{
unsigned char *pimg, *pf;
float tmp, conv;
int i, j;
pf = filtd;
pimg = img;
/* Do first line */
for(j=0; j<cols; j++, pimg++) {
conv = (float)gain * ((float) *pimg * (float)2 + (float)2 * (float)*(pimg+cols)) / (float)4.0;
tmp = (conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
pimg+= (s-1)*cols;
/* Do image center */
for(i=s; i<rows-1; i+=s) {
for(j=0; j<cols; j++, pimg++) {
conv = (float)gain * ((float)*(pimg-cols) + (float)*pimg * (float)2 + (float)*(pimg+cols)) / (float)4.0;
tmp = (conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
pimg+=(s-1)*cols;
}
/* Do last line if s equals one */
if(s==1) {
for(j=0; j<cols; j++, pimg++) {
conv = (float)gain * ((float)*pimg * (float)2 + (float)2 * (float)*(pimg-cols)) / (float)4.0;
tmp = (float)(conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
}
}
/******************************************************************
* Function vfilt5
* Filters img vertically with a 5 tap gaussian filter, subsampling by s.
* rows, cols are the dimensions of img
*****************************************************************/
static void vfilt5(unsigned char *img, unsigned char *filtd,
unsigned char s, unsigned char gain,
int rows, int cols)
{
unsigned char *pimg, *pf;
float conv, tmp;
int i, j, tcols;
pf = filtd;
pimg = img;
tcols = 2*cols;
for(i=0; i<rows; i+=s) {
for(j=0; j<cols; j++, pimg++) {
if (i==0)
conv = (float)gain * ((float)6.0 * (float)*pimg + (float)8.0 * (float)*(pimg+cols) + (float)2.0 * (float)*(pimg+tcols)) / (float)16.0;
else if (i==1)
conv = (float)gain * ((float)4.0 * (float)*(pimg-cols) + (float)6.0 * (float)*pimg + (float)4.0 * (float)*(pimg+cols) + (float)2.0 * (float)*(pimg+tcols)) / (float)16.0;
else if (i==rows-2)
conv = (float)gain * ((float)2.0 * (float)*(pimg-tcols) + (float)4.0 * (float)*(pimg-cols) + (float)6.0 * (float)*pimg + (float)4.0 * (float)*(pimg+cols)) / (float)16.0;
else if (i==rows-1)
conv = (float)gain * ((float)2.0 * (float)*(pimg-tcols) + (float)8.0 * (float)*(pimg-cols) + (float)6.0 * (float)*pimg) / (float)16.0;
else
conv = (float)gain * (float)(*(pimg-tcols) + (float)4.0 * (float)*(pimg-cols) + (float)6.0 * (float)*pimg +
(float)4.0 * (float)*(pimg+cols) + (float)*(pimg+tcols)) / (float)16.0;
tmp = (float)(conv > 255 ? 255 : conv);
*(pf++) = (unsigned char)(tmp < 0 ? 0 : tmp);
}
pimg+=(s-1)*cols;
}
}
/******************************************************************
* Function lowpass
* 2D low pass filtering of img into lp. rows,
* cols are the dimensions of img.
******************************************************************/
static void lowpass(unsigned char *img, unsigned char *lp,
int rows, int cols, int ntaps)
{
unsigned char *tmp;
if (!(tmp = (unsigned char *)ScAlloc(rows*cols))) {
/* fprintf(stderr,"ScAlloc failed\n");
exit(-1); */
return;
}
switch (ntaps) {
case 3:
hfilt121(img, tmp, 1, 1, rows, cols);
vfilt121(tmp, lp, 1, 1, rows, cols);
break;
case 5:
hfilt5(img, tmp, 1, 1, rows, cols);
vfilt5(tmp, lp, 1, 1, rows, cols);
break;
default:
/* printf("Unknown filter in lowpass\n");
exit(0); */
ScFree(tmp);
return;
}
ScFree(tmp);
}
/******************************************************************
* Function reduce
* 2D low pass filtering and subsampling by two of img into red. rows,
* cols are the dimensions of img.
******************************************************************/
static void reduce(unsigned char *img, unsigned char *red,
int rows, int cols, int ntaps)
{
unsigned char *tmp;
if (!(tmp = (unsigned char *)ScAlloc(rows*cols/2))) {
/* fprintf(stderr,"ScAlloc failed\n");
exit(-1); */
return;
}
switch (ntaps) {
case 3:
hfilt121(img, tmp, 2, 1, rows, cols);
vfilt121(tmp, red, 2, 1, rows, cols>>1);
break;
case 5:
hfilt5(img, tmp, 2, 1, rows, cols);
vfilt5(tmp, red, 2, 1, rows, cols>>1);
break;
default:
/*
printf("Unknown filter in reduce\n");
exit(0); */
ScFree(tmp);
return;
}
ScFree(tmp);
}
/******************************************************************
* Function hpad
* Zero-pads img horizontaly by the factor s. Returns zero-paded
* image in zp. rows, cols are the dimensions of img
*****************************************************************/
static void hpad(unsigned char *img, unsigned char *zp,
unsigned char s,
int rows, int cols, char mode)
{
int i, j;
unsigned char *pf, *pimg, fill;
switch (mode) {
case 'l':
fill = 0;
break;
case 'c':
fill = 0;
break;
default:
/*
printf("Unknown fill mode in hpad\n");
exit(0);
*/
return;
}
pimg = img;
pf = zp;
for(i=0; i<rows; i++)
for(j=0; j<cols*s; j++)
*(pf++) = (j%s ? fill: *(pimg++));
}
/******************************************************************
* Function vpad
* Zero-pads img verticaly by the factor s. Returns zero-paded
* image in zp. rows, cols are the dimensions of img
*****************************************************************/
static void vpad(unsigned char *img, unsigned char *zp,
unsigned char s,
int rows, int cols, char mode)
{
int i, j;
unsigned char *pf, *pimg, fill;
switch (mode) {
case 'l':
fill = 0;
break;
case 'c':
fill = 0;
break;
default:
/*
printf("Unknown fill mode in hpad\n");
exit(0); */
return;
}
pimg = img;
pf = zp;
for(i=0; i<rows*s; i++)
for(j=0; j<cols; j++)
*(pf++) = (i%s ? fill: *(pimg++));
}
/******************************************************************
* Function Expand
* 2D upsampling by two and low pass filtering of img into exp. rows,
* cols are the dimensions of img.
******************************************************************/
static void Expand(unsigned char *img, unsigned char *exp,
int rows, int cols, char mode, int ntaps)
{
unsigned char *tmp, *tmp2, *tmp3;
if (!(tmp = (unsigned char *)ScAlloc(rows*cols*2))) {
/*
fprintf(stderr,"ScAlloc failed\n");
exit(-1); */
return;
}
hpad(img, tmp, 2, rows, cols, mode);
if (!(tmp2 = (unsigned char *)ScAlloc(rows*cols*2))) {
/* fprintf(stderr,"ScAlloc failed\n");
exit(-1); */
return;
}
switch (ntaps) {
case 3:
hfilt121(tmp, tmp2, 1, 2, rows, cols<<1);
break;
case 5:
hfilt5(tmp, tmp2, 1, 2, rows, cols<<1);
break;
default:
/*
printf("Unknown filter in Expand\n");
exit(0); */
return;
}
if (!(tmp3 = (unsigned char *)ScAlloc(rows*cols*4))) {
/*
fprintf(stderr,"ScAlloc failed\n");
exit(-1);
*/
return;
}
vpad(tmp2, tmp3, 2, rows, cols<<1, mode);
switch (ntaps) {
case 3:
vfilt121(tmp3, exp, 1, 2, rows<<1, cols<<1);
break;
case 5:
vfilt5(tmp3, exp, 1, 2, rows<<1, cols<<1);
break;
default:
/*
printf("Unknown filter in Expand\n");
exit(0); */
return;
}
ScFree(tmp); ScFree(tmp2); ScFree(tmp3);
}
/*****************************************************************
* Function gaussp
* Builds a Gaussian pyramid of depth levels.
*****************************************************************/
static void gaussp(unsigned char *img, unsigned char **pyr,
int depth, int rows, int cols, int ntaps)
{
int d;
memcpy(pyr[0], img, rows*cols);
for(d=1; d<depth; d++) {
reduce(pyr[d-1], pyr[d], rows, cols, ntaps);
rows /= 2;
cols /= 2;
}
}
/*****************************************************************
* Function palloc
* Allocates memory for a Gaussian pyramid of depth levels.
* Higher resolution is level 0, with dimensions rows, cols.
*****************************************************************/
static unsigned char **palloc(int depth, int rows, int cols)
{
int d;
unsigned char **pyr;
if (!(pyr = (unsigned char **)ScAlloc(depth*sizeof(unsigned char *)))) {
/*
fprintf(stderr,"ScAlloc failed\n");
exit(-1);
*/
return(NULL);
}
for(d=0; d<depth; d++) {
if (!(pyr[d] = (unsigned char *)ScAlloc(rows*cols))) {
/*
fprintf(stderr,"ScAlloc failed\n");
exit(-1);
*/
return(NULL);
}
rows /= 2;
cols /= 2;
}
return pyr;
}
/****************************************************************
* Function PictPyr
* Buids a Gaussian pyramid of picture images with depth levels.
****************************************************************/
static H263_PictImage **PictPyr(H263_PictImage *img, int depth, int rows, int cols, int ntaps)
{
unsigned char **tmp;
H263_PictImage ** PictPyr;
int d;
if (!(PictPyr = (H263_PictImage **)ScAlloc(depth*sizeof(H263_PictImage *)))) {
/*
fprintf(stderr,"ScAlloc failed\n");
exit(-1);
*/
return(NULL);
}
for(d=0; d< depth; d++) {
if ((PictPyr[d] = (H263_PictImage *)ScAlloc(sizeof(H263_PictImage))) == NULL) {
/*
fprintf(stderr,"Couldn't allocate (PictImage *)\n");
exit(-1);
*/
return(NULL);
}
}
/* Luminance */
tmp = palloc(depth, rows, cols);
gaussp(img->lum, tmp, depth, rows, cols, ntaps);
for(d=0; d<depth; d++) PictPyr[d]->lum = tmp[d];
rows/=2; cols/=2;
/* Chroma 1 */
tmp = palloc(depth, rows, cols);
gaussp(img->Cr, tmp, depth, rows, cols, ntaps);
for(d=0; d<depth; d++) PictPyr[d]->Cr = tmp[d];
/* Chroma 2 */
tmp = palloc(depth, rows, cols);
gaussp(img->Cb, tmp, depth, rows, cols, ntaps);
for(d=0; d<depth; d++) PictPyr[d]->Cb = tmp[d];
ScFree(tmp);
return PictPyr;
}
/*****************************************************************
* Function expyr
* Expands the pyramid channels to full resolution. rows, cols
* are the dimensions of the expanded images, and the full resolution
* layer of the pyramid.
*****************************************************************/
static void expyr(unsigned char **pyr, unsigned char **filtd,
int depth, int rows, int cols,
char mode, int ntaps)
{
int d, l, r, c;
r = rows; c = cols;
memcpy(filtd[0], pyr[0], rows*cols);
for(d=1; d<depth; d++) {
r /= 2;
c /= 2;
for(l=d; l>0; l--) Expand(pyr[d], pyr[d-1], r, c, mode, ntaps);
memcpy(filtd[d], pyr[0], rows*cols);
}
}
/*****************************************************************
* Function GaussFilt
* Builds an array of successively more low pass filtered images
* by constructing a gaussian pyramid and expanding each level
* to full resolution
*****************************************************************/
static H263_PictImage **GaussFilt(H263_PictImage *img, int depth, int rows,
int cols, int ntaps)
{
int d;
H263_PictImage **PictFiltd;
unsigned char **tmp, **filtd;
PictFiltd = (H263_PictImage **) ScAlloc(depth*sizeof(H263_PictImage *));
for(d=0; d<depth; d++) {
PictFiltd[d] = sv_H263InitImage(rows*cols);
}
/* Luminance */
filtd = (unsigned char **) ScAlloc(depth*sizeof(unsigned char *));
for(d=0; d<depth; d++) filtd[d] = (unsigned char *) ScAlloc(rows * cols);
tmp = palloc(depth, rows, cols);
gaussp(img->lum, tmp, depth, rows, cols, ntaps);
expyr(tmp, filtd, depth, rows, cols, 'l', ntaps);
for(d=0; d<depth; d++) memcpy(PictFiltd[d]->lum, filtd[d], rows*cols);
for(d=0; d<depth; d++) {
ScFree(tmp[d]);
ScFree(filtd[d]);
}
ScFree(tmp);
ScFree(filtd);
rows/=2; cols/=2;
/* Chroma 1 */
filtd = (unsigned char **) ScAlloc(depth*sizeof(unsigned char *));
for(d=0; d<depth; d++) filtd[d] = (unsigned char *) ScAlloc(rows * cols);
tmp = palloc(depth, rows, cols);
gaussp(img->Cr, tmp, depth, rows, cols, ntaps);
expyr(tmp, filtd, depth, rows, cols, 'c', ntaps);
for(d=0; d<depth; d++) memcpy(PictFiltd[d]->Cr, filtd[d], rows*cols);
for(d=0; d<depth; d++) {
ScFree(tmp[d]);
ScFree(filtd[d]);
}
ScFree((void *) tmp);
ScFree((void *) filtd);
/* Chroma 2 */
filtd = (unsigned char **) ScAlloc(depth*sizeof(unsigned char *));
for(d=0; d<depth; d++) filtd[d] = (unsigned char *) ScAlloc(rows * cols);
tmp = palloc(depth, rows, cols);
gaussp(img->Cb, tmp, depth, rows, cols, ntaps);
expyr(tmp, filtd, depth, rows, cols, 'c', ntaps);
for(d=0; d<depth; d++) memcpy(PictFiltd[d]->Cb, filtd[d], rows*cols);
for(d=0; d<depth; d++) {
ScFree(tmp[d]);
ScFree(filtd[d]);
}
ScFree((void *) tmp);
ScFree((void *) filtd);
return PictFiltd;
}
/*****************************************************************
* Function GaussLayers
* Builds an array of successively more low pass filtered images
*****************************************************************/
H263_PictImage **svH263GaussLayers(H263_PictImage *img, int depth, int rows, int cols, int ntaps)
{
int d;
H263_PictImage **PictFiltd;
PictFiltd = (H263_PictImage **) ScAlloc(depth*sizeof(H263_PictImage *));
for(d=0; d<depth; d++) {
PictFiltd[d] = sv_H263InitImage(rows*cols);
}
/* Luminance */
memcpy(PictFiltd[0]->lum, img->lum, rows*cols);
for(d=1; d<depth; d++)
lowpass(PictFiltd[d-1]->lum, PictFiltd[d]->lum, rows, cols, ntaps);
rows/=2; cols/=2;
/* Chroma 1 */
memcpy(PictFiltd[0]->Cr, img->Cr, rows*cols);
for(d=1; d<depth; d++)
lowpass(PictFiltd[d-1]->Cr, PictFiltd[d]->Cr, rows, cols, ntaps);
/* Chroma 2 */
memcpy(PictFiltd[0]->Cb, img->Cb, rows*cols);
for(d=1; d<depth; d++)
lowpass(PictFiltd[d-1]->Cb, PictFiltd[d]->Cb, rows, cols, ntaps);
return PictFiltd;
}