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

3072 lines
104 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* File: sv_h263_encode.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. **
******************************************************************************/
/*
#define _SLIBDEBUG_
*/
#include <math.h>
#include "sv_h263.h"
#include "proto.h"
#include "SC_err.h"
#include "SC_conv.h"
#ifndef USE_C
#include "perr.h"
#endif
#ifdef WIN32
#include <mmsystem.h>
#endif
#ifdef _SLIBDEBUG_
#include "sc_debug.h"
#define _SNR_ 1 /* calculate SNR */
#define _DEBUG_ 0 /* detailed debuging statements */
#define _VERBOSE_ 0 /* show progress */
#define _VERIFY_ 0 /* verify correct operation */
#define _WARN_ 0 /* warnings about strange behavior */
#define _WRITE_ 0 /* write DEBUG.IMG */
#include <stdio.h>
int DEBUGIMG = -1;
#endif /* _SLIBDEBUG_ */
#define NTAPS 5
static void SetDefPrefLevel(SvH263CompressInfo_t *H263Info);
static void SetDefThresh(SvH263CompressInfo_t *H263Info);
static void CheckPrefLevel(SvH263CompressInfo_t *H263Info, int depth) ;
static short sv_H263MBDecode(SvH263CompressInfo_t *H263Info, short *qcoeff,
H263_MB_Structure *mb_recon, int QP, int I, int CBP,
unsigned dword quality);
static int sv_H263MBEncode(H263_MB_Structure *mb_orig, int QP, int I, int *CBP,
short *qcoeff, unsigned dword quality);
static int NextTwoPB(SvH263CompressInfo_t *H263Info,
H263_PictImage *next2, H263_PictImage *next1,
H263_PictImage *prev,
int bskip, int pskip, int seek_dist);
static SvStatus_t sv_H263CodeOneOrTwo(SvCodecInfo_t *Info, int QP, int frameskip,
H263_Bits *bits, H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2]);
#ifdef _SNR_
static void ComputeSNR(SvH263CompressInfo_t *H263Info,
H263_PictImage *im1, H263_PictImage *im2,
int lines, int pels);
static void PrintResult(SvH263CompressInfo_t *H263Info, H263_Bits *bits, int num_units, int num);
#endif
static SvStatus_t sv_H263WriteExtBitstream(SvH263CompressInfo_t *H263Info,
ScBitstream_t *bs);
// #define GOB_RATE_CONTROL
#ifdef GOB_RATE_CONTROL
void sv_H263GOBInitRateCntrl();
void sv_H263GOBUpdateRateCntrl(int bits);
int sv_H263GOBInitQP(float bit_rate, float target_frame_rate, float QP_mean);
int sv_H263GOBUpdateQP(int mb, float QP_mean, float bit_rate,int mb_width, int mb_height, int bitcount,
int NOgob, int *VARgob, int pb_frame) ;
#endif
void sv_H263UpdateQuality(SvCodecInfo_t *Info)
{
if (Info->mode == SV_H263_ENCODE)
{
SvH263CompressInfo_t *H263Info=Info->h263comp;
unsigned dword imagesize=Info->Width*Info->Height;
unsigned dword bit_rate=H263Info->bit_rate;
unsigned dword calc_quality;
if (H263Info->quality==0) /* no quality setting */
{
calc_quality=H263_MAX_CALC_QUALITY;
}
else if (bit_rate==0 || imagesize==0) /* variable bitrate */
{
/* make the quant settings directly proportional to the quality */
H263Info->QPI=(((100-H263Info->quality)*31)/100)+1;
if (H263Info->QPI>31)
H263Info->QPI=31;
H263Info->QP_init=H263Info->QPI;
calc_quality=H263_MAX_CALC_QUALITY;
}
else /* fixed bitrate */
{
/* Using calc_quality you get:
bitrate framerate imagesize quality calc_quality QPI
-------- ---------- ---------- ------- ------------ ---
57400 7 352x288 100% 82 9
57400 15 352x288 100% 38 22
13300 7 352x288 100% 19 26
13300 15 352x288 100% 8 28
13300 7 176x144 100% 79 10
13300 15 176x144 100% 36 22
*/
calc_quality=(bit_rate*H263Info->quality)/(unsigned int)(H263Info->frame_rate*100);
calc_quality/=imagesize/1024;
if (calc_quality<H263_MIN_CALC_QUALITY)
calc_quality=H263_MIN_CALC_QUALITY;
else if (calc_quality>H263_MAX_CALC_QUALITY)
calc_quality=H263_MAX_CALC_QUALITY;
/* make the quant settings directly proportional to the calc_quality */
if (calc_quality>200)
H263Info->QPI=1;
else
{
H263Info->QPI=(((200-calc_quality)*31)/200)+1;
if (H263Info->QPI>31)
H263Info->QPI=31;
}
H263Info->QP=H263Info->QP_init=H263Info->QPI;
}
H263Info->calc_quality=calc_quality;
}
}
static SvStatus_t convert_to_411(SvCodecInfo_t *Info,
u_char *dest_buff, u_char *ImagePtr)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
unsigned long size = (Info->InputFormat.biWidth * Info->InputFormat.biHeight) ;
if (IsYUV422Packed(Info->InputFormat.biCompression))
{
SvStatus_t status;
/* Input is in NTSC format, convert */
if ((Info->InputFormat.biWidth == NTSC_WIDTH) &&
(Info->InputFormat.biHeight == NTSC_HEIGHT))
status = ScConvertNTSC422toCIF411((unsigned char *)ImagePtr,
(unsigned char *)(dest_buff),
(unsigned char *)(dest_buff + size),
(unsigned char *)(dest_buff + size +(size/4)),
(int) Info->InputFormat.biWidth);
else
status = ScConvert422ToYUV_char_C(ImagePtr,
(unsigned char *)(dest_buff), /* Y */
(unsigned char *)(dest_buff+size), /* U */
(unsigned char *)(dest_buff+size+(size/4)), /* V */
Info->InputFormat.biWidth,Info->InputFormat.biHeight);
return(status);
}
else if (IsYUV411Sep(Info->InputFormat.biCompression))
{
/*
* If YUV 12 SEP, Not converting, so just copy data to the luminance
* and chrominance appropriatelyi
*/
memcpy(dest_buff, ImagePtr, (H263Info->pels*H263Info->lines*3)/2);
}
else if (IsYUV422Sep(Info->InputFormat.biCompression))
{
_SlibDebug(_DEBUG_, printf("ScConvert422PlanarTo411()\n") );
ScConvert422PlanarTo411(ImagePtr,
dest_buff, dest_buff+size, (dest_buff+size+(size/4)),
Info->Width,Info->Height);
}
else
{
_SlibDebug(_WARN_, printf("Unsupported Video format\n") );
return(SvErrorUnrecognizedFormat);
}
return(SvErrorNone);
}
/**********************************************************************
*
* Name: InitImage
* Description: Allocates memory for structure of 4:2:0-image
*
* Input: image size
* Returns: pointer to new structure
* Side effects: memory allocated to structure
*
***********************************************************************/
H263_PictImage *sv_H263InitImage(int size)
{
H263_PictImage *new;
unsigned char *image;
if ((new = (H263_PictImage *)ScAlloc(sizeof(H263_PictImage))) == NULL) {
svH263Error("Couldn't allocate (PictImage *)\n");
return(NULL);
}
if ((image = (unsigned char *)ScPaMalloc((sizeof(char)*size*3)/2)) == NULL) {
svH263Error("Couldn't allocate image\n");
return(NULL);
}
new->lum = image;
new->Cb = image+size;
new->Cr = image+(size*5)/4;
_SlibDebug(_DEBUG_, ScDebugPrintf(NULL,"sv_H263InitImage() %p\n", new) );
return new;
}
/**********************************************************************
*
* Name: FreeImage
* Description: Frees memory allocated to structure of 4:2:0-image
*
* Input: pointer to structure
* Returns:
* Side effects: memory of structure freed
*
***********************************************************************/
void sv_H263FreeImage(H263_PictImage *image)
{
_SlibDebug(_DEBUG_, ScDebugPrintf(NULL,"sv_H263FreeImage(%p)\n", image) );
ScPaFree(image->lum);
/* ScFree(image->Cr);
ScPaFree(image->Cb); */
ScFree(image);
}
/******************************************************************
* Set the PREF_LEVEL matrix to the default values
******************************************************************/
static void SetDefPrefLevel(SvH263CompressInfo_t *H263Info)
{
int i, j;
unsigned char H263_DEF_PREF_LEVEL[4][3] = {{0, 0, 1},
{0, 1, 1},
{0, 1, 2},
{0, 2, 2}};
for(i=0; i<4; i++) {
for(j=0; j<3; j++) {
H263Info->PREF_LEVEL[i][j] = H263_DEF_PREF_LEVEL[i][j];
}
}
}
/*****************************************************************
* Set the Threshold vectors to the default values
*****************************************************************/
static void SetDefThresh(SvH263CompressInfo_t *H263Info)
{
int i;
unsigned char H263_DEF_MOTRESH[4]= {0, 2, 4, 7};
int H263_DEF_PETRESH[3]= {2500, 3500, 6000};
for(i=0; i<4; i++) {
H263Info->MOTresh[i] = H263_DEF_MOTRESH[i];
}
for(i=0; i<3; i++) {
H263Info->PETresh[i] = H263_DEF_PETRESH[i];
}
}
/***********************************************************************
* Cheks if all the selections in PREF_LEVEL are consistent with depth.
***********************************************************************/
static void CheckPrefLevel(SvH263CompressInfo_t *H263Info, int depth)
{
int i, j;
for(i=0; i<4; i++) {
for(j=0; j<3; j++) {
if (H263Info->PREF_LEVEL[i][j]>depth-1) H263Info->PREF_LEVEL[i][j] = depth-1;
}
}
}
static int svH263zeroflush(ScBitstream_t *BSOut)
{
int bits;
bits = (int)(ScBSBitPosition(BSOut)%8);
if(bits) {
bits = 8-bits;
ScBSPutBits(BSOut, 0, bits) ;
}
return bits;
}
/***************************************************/
/***************************************************/
static SvStatus_t sv_H263Compress(SvCodecInfo_t *Info);
extern int arith_used;
SvStatus_t svH263Compress(SvCodecInfo_t *Info, u_char *ImagePtr)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
ScBitstream_t *BSOut=Info->BSOut;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg,"sv_H263Compress() bytepos=%ld\n",
ScBSBytePosition(Info->BSOut)) );
if (H263Info->frame_no == H263Info->start) /* Encode the first frame */
{
sv_H263UpdateQuality(Info); /* in case image size has changed */
/* Intra image */
/* svH263ReadImage(H263Info->curr_image, H263Info->start, H263Info->video_file); */
convert_to_411(Info, H263Info->curr_image->lum, ImagePtr);
H263Info->pic->picture_coding_type = H263_PCT_INTRA;
H263Info->pic->QUANT = H263Info->QPI;
if (H263Info->curr_recon==NULL)
H263Info->curr_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
sv_H263CodeOneIntra(Info, H263Info->curr_image, H263Info->curr_recon, H263Info->QPI,
H263Info->bits, H263Info->pic);
#ifdef _SNR_
ComputeSNR(H263Info, H263Info->curr_image, H263Info->curr_recon,
H263Info->lines, H263Info->pels);
#endif
if (arith_used)
{
H263Info->bits->header += sv_H263AREncoderFlush(H263Info, BSOut);
arith_used = 0;
}
H263Info->bits->header += svH263zeroflush(BSOut); /* pictures shall be byte aligned */
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Frame %d = I frame\n", H263Info->frames) );
sv_H263ZeroRes(H263Info->b_res);
sv_H263AddBitsPicture(H263Info->bits);
/* PrintResult(H263Info->bits, 1, 1); */
memcpy(H263Info->intra_bits,H263Info->bits,sizeof(H263_Bits));
sv_H263ZeroBits(H263Info->total_bits);
sv_H263ZeroRes(H263Info->total_res);
sv_H263ZeroRes(H263Info->res);
H263Info->buffer_fullness = H263Info->intra_bits->total;
/* number of seconds to encode */
H263Info->seconds = (H263Info->end - H263Info->start + H263Info->chosen_frameskip)/H263Info->frame_rate;
H263Info->first_frameskip = H263Info->chosen_frameskip;
H263Info->distance_to_next_frame = H263Info->first_frameskip;
_SlibDebug(_WARN_ && H263Info->first_frameskip>256,
ScDebugPrintf(H263Info->dbg, "Warning: frameskip > 256\n") );
H263Info->pic->picture_coding_type = H263_PCT_INTER;
H263Info->pic->QUANT = H263Info->QP;
H263Info->bdist = H263Info->chosen_frameskip;
/* always encode the first frame after intra as P frame.
This is not necessary, but something we chose to make
the adaptive PB frames calculations a bit simpler */
if (H263Info->pb_frames) {
H263Info->pic->PB = 0;
H263Info->pdist = 2*H263Info->chosen_frameskip - H263Info->bdist;
}
/* point to the 2nd frame */
H263Info->frame_no = H263Info->start + H263Info->first_frameskip;
H263Info->frames++;
if (H263Info->extbitstream)
{
SvStatus_t status;
status = sv_H263WriteExtBitstream(H263Info, BSOut);
if (status!=SvErrorNone)
return(status);
}
}
else
{ /* the rest of frames */
/***** Main loop *****/
/* Set QP to pic->QUANT from previous encoded picture */
H263Info->QP = H263Info->pic->QUANT;
H263Info->next_frameskip = H263Info->distance_to_next_frame;
if (!H263Info->pb_frames)
{
H263_PictImage *tmpimage;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Frame %d = P frame\n", H263Info->frames) );
if (H263Info->prev_image==NULL)
H263Info->prev_image = sv_H263InitImage(H263Info->pels*H263Info->lines);
/* swap current and prev images */
tmpimage=H263Info->prev_image;
H263Info->prev_image = H263Info->curr_image;
H263Info->curr_image = tmpimage;
/* swap recon images */
if (H263Info->prev_recon==NULL)
H263Info->prev_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
if (H263Info->curr_recon==NULL)
H263Info->curr_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
tmpimage=H263Info->curr_recon;
H263Info->curr_recon = H263Info->prev_recon;
H263Info->prev_recon = tmpimage;
convert_to_411(Info, H263Info->curr_image->lum, ImagePtr);
H263Info->frames++;
H263Info->next_frameskip = H263Info->pdist;
return(sv_H263Compress(Info)); /* Encode P */
}
else if ((H263Info->frames%2)==1) /* this is a B frame */
{
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Frame %d = B frame\n", H263Info->frames) );
H263Info->PPFlag = 0;
H263Info->bdist = H263Info->chosen_frameskip;
H263Info->pdist = 2*H263Info->chosen_frameskip - H263Info->bdist;
H263Info->pic->TRB = (int)(H263Info->bdist * H263Info->orig_frameskip);
_SlibDebug(_WARN_ && H263Info->pic->TRB>8,
ScDebugPrintf(H263Info->dbg, "distance too large for B-frame\n") );
/* Read the frame to be coded as B */
if (H263Info->B_image==NULL)
H263Info->B_image = sv_H263InitImage(H263Info->pels*H263Info->lines);
if (H263Info->B_recon==NULL)
H263Info->B_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
/* svH263ReadImage(H263Info->B_image,H263Info->frame_no - H263Info->pdist,H263Info->video_file); */
convert_to_411(Info, H263Info->B_image->lum, ImagePtr);
H263Info->first_loop_finished = 1;
H263Info->pic->PB = 1;
H263Info->frames++;
/* need to reorder P+B frames - HWG */
/* return now, we'll get the B frame on the next Compress call */
return(SvErrorNone);
}
else /* this is a P frame of a PB or PP pair */
{
H263_PictImage *tmpimage;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Frame %d = P frame\n", H263Info->frames) );
if (H263Info->prev_image==NULL)
H263Info->prev_image = sv_H263InitImage(H263Info->pels*H263Info->lines);
/* swap current and prev images */
tmpimage=H263Info->prev_image;
H263Info->prev_image = H263Info->curr_image;
H263Info->curr_image = tmpimage;
/* swap recon images */
if (H263Info->prev_recon==NULL)
H263Info->prev_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
if (H263Info->curr_recon==NULL)
H263Info->curr_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
tmpimage=H263Info->curr_recon;
H263Info->curr_recon = H263Info->prev_recon;
H263Info->prev_recon = tmpimage;
/* svH263ReadImage(H263Info->curr_image, H263Info->frame_no, H263Info->video_file); */
convert_to_411(Info, H263Info->curr_image->lum, ImagePtr);
if (H263Info->pic->TRB > 8 || !NextTwoPB(H263Info, H263Info->curr_image,
H263Info->B_image, H263Info->prev_image,
H263Info->bdist, H263Info->pdist, H263Info->pic->seek_dist))
{
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Encode PP\n") );
H263Info->PPFlag = 1;
/* curr_image and B_image were not suitable to be coded
as a PB-frame - encoding as two P-frames instead */
H263Info->pic->PB = 0;
H263Info->next_frameskip = H263Info->bdist;
/* swap B and current images - B_image gets encoded first as P frame */
tmpimage = H263Info->curr_image;
H263Info->curr_image = H263Info->B_image;
H263Info->B_image = tmpimage;
sv_H263Compress(Info); /* Encode first P */
H263Info->next_frameskip = H263Info->pdist;
/* swap current and prev images */
tmpimage=H263Info->prev_image;
H263Info->prev_image = H263Info->curr_image;
H263Info->curr_image = tmpimage;
/* swap current and B images */
tmpimage=H263Info->B_image;
H263Info->B_image = H263Info->curr_image;
H263Info->curr_image = tmpimage;
/* swap recon images */
tmpimage=H263Info->curr_recon;
H263Info->curr_recon = H263Info->prev_recon;
H263Info->prev_recon = tmpimage;
sv_H263Compress(Info); /* Encode second P */
H263Info->frames++;
H263Info->PPFlag = 0;
}
else
{
H263Info->pic->PB=1;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Encode PB\n") );
H263Info->frames++;
return(sv_H263Compress(Info)); /* Encode PB */
}
}
} /* the rest of frames */
return(SvErrorNone);
}
static SvStatus_t sv_H263Compress(SvCodecInfo_t *Info)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
ScBitstream_t *BSOut=Info->BSOut;
H263Info->bframes += (H263Info->pic->PB ? 1 : 0);
H263Info->pframes++;
/* Temporal Reference is the distance between encoded frames compared
the reference picture rate which is 25.0 or 30 fps */
if (H263Info->next_frameskip*H263Info->orig_frameskip > 256)
svH263Error("Warning: frameskip > 256\n");
/* pic->TR += ((H263Info->next_frameskip*(int)H263Info->orig_frameskip) % 256); */
H263Info->pic->TR = ((int) ( (int)((float)(H263Info->frame_no-H263Info->start)*H263Info->orig_frameskip) ) % 256);
if (H263Info->pic->PB) { /* Code two frames as a PB-frame */
if (H263Info->vsnr && H263Info->B_recon==NULL)
H263Info->B_recon = sv_H263InitImage(H263Info->pels*H263Info->lines);
/*
fprintf(stdout,"Coding PB frames %d and %d... ",
H263Info->frame_no - H263Info->pdist, H263Info->frame_no);
*/
#if 0
if(H263Info->prefilter) {
if(H263Info->StaticPref)
H263Info->B_clean = svH263AdaptClean(H263Info->B_image, H263Info->lines, H263Info->pels, -1, -1);
else H263Info->B_clean = H263Info->B_image;
if(H263Info->PrefPyrType == H263_GAUSS)
H263Info->B_filtd = svH263GaussLayers(H263Info->B_clean, H263_PYR_DEPTH, H263Info->lines, H263Info->pels, NTAPS);
else if(H263Info->PrefPyrType == H263_MORPH)
H263Info->B_filtd = svH263MorphLayers(H263Info->B_clean, H263_PYR_DEPTH, H263Info->lines, H263Info->pels, 2);
if(H263Info->StaticPref) sv_H263FreeImage(H263Info->B_clean);
}
fflush(stdout);
#endif
}
else { /* Code the next frame as a normal P-frame */
/* fprintf(stdout,"Coding P frame %d... ", H263Info->frame_no); */
/* fflush(stdout); */
}
/* if (H263Info->curr_recon==NULL)
H263Info->curr_recon = sv_H263InitImage(H263Info->pels*H263Info->lines); HWG */
/* changed by Nuno on 06/27/96 to support prefiltering */
#if 0
if(H263Info->prefilter) {
int m;
if(H263Info->StaticPref)
H263Info->curr_clean = svH263AdaptClean(H263Info->curr_image, H263Info->lines, H263Info->pels, -1, -1);
else H263Info->curr_clean = H263Info->curr_image;
if(H263Info->PrefPyrType == H263_GAUSS)
H263Info->curr_filtd = svH263GaussLayers(H263Info->curr_clean, H263_PYR_DEPTH, H263Info->lines, H263Info->pels, NTAPS);
else if(H263Info->PrefPyrType == H263_MORPH)
H263Info->curr_filtd = svH263MorphLayers(H263Info->curr_clean, H263_PYR_DEPTH, H263Info->lines, H263Info->pels, 2);
if(H263Info->StaticPref) sv_H263FreeImage(H263Info->curr_clean);
PreFilterLevel = (unsigned char **) ScAlloc(H263Info->lines/H263_MB_SIZE*sizeof(char *));
for(m=0; m<H263Info->mb_height; m++)
PreFilterLevel[m]= (unsigned char *) ScAlloc(H263Info->pels/H263_MB_SIZE);
}
#endif
sv_H263CodeOneOrTwo(Info, H263Info->QP,
(int)(H263Info->next_frameskip*H263Info->orig_frameskip),
H263Info->bits, H263Info->MV);
#if 0
if(H263Info->prefilter) {
int i, j;
fprintf(stdout, "Prefiltering level matrix\n");
for(i=0; i<H263Info->mb_height; i++) {
for(j=0; j<H263Info->mb_width; j++) {
fprintf(stdout,"%4d ", PreFilterLevel[i][j]);
}
fprintf(stdout,"\n");
}
}
#endif
/* fprintf(stdout,"done\n"); */
_SlibDebug(_VERBOSE_ && H263Info->bit_rate != 0,
ScDebugPrintf(H263Info->dbg, "Inter QP: %d\n", H263Info->QP) );
/* fflush(stdout); */
if (arith_used) {
H263Info->bits->header += sv_H263AREncoderFlush(H263Info, BSOut);
arith_used = 0;
}
H263Info->bits->header += svH263zeroflush(BSOut); /* pictures shall be byte aligned */
sv_H263AddBitsPicture(H263Info->bits);
sv_H263AddBits(H263Info->total_bits, H263Info->bits);
#ifdef GOB_RATE_CONTROL
if (H263Info->bit_rate != 0) {
sv_H263GOBUpdateRateCntrl(H263Info->bits->total);
}
#else
/* Aim for the H263_targetrate with a once per frame rate control scheme */
if (H263Info->bit_rate != 0 &&
H263Info->frame_no - H263Info->start >
(H263Info->end - H263Info->start) * H263Info->start_rate_control/100.0)
{
/* when generating the MPEG-4 anchors, rate control was started
after 70% of the sequence was finished.
Set H263Info->start_rate_control with option "-R <n>" */
H263Info->buffer_fullness += H263Info->bits->total;
H263Info->buffer_frames_stored = H263Info->frame_no;
H263Info->pic->QUANT = sv_H263FrameUpdateQP(H263Info->buffer_fullness,
H263Info->bits->total / (H263Info->pic->PB?2:1),
(H263Info->end-H263Info->buffer_frames_stored) / H263Info->chosen_frameskip
+ H263Info->PPFlag,
H263Info->QP, H263Info->bit_rate, H263Info->seconds);
}
#endif
if (H263Info->pic->PB)
{
#ifdef _SNR_
if (H263Info->B_recon)
ComputeSNR(H263Info, H263Info->B_image, H263Info->B_recon,
H263Info->lines, H263Info->pels);
#endif
/* fprintf(stdout,"Results for B-frame:\n");*/
/* sv_H263FreeImage(H263Info->B_image); HWG */
}
#if 0
if(H263Info->prefilter) ScFree(H263Info->B_filtd);
#endif
H263Info->distance_to_next_frame = (H263Info->PPFlag ? H263Info->pdist :
(H263Info->pb_frames ? 2*H263Info->chosen_frameskip:
H263Info->chosen_frameskip));
/* if (H263Info->pb_frames) H263Info->pic->PB = 1; */
/* fprintf(stdout,"Results for P-frame:\n"); */
#ifdef _SNR_
ComputeSNR(H263Info, H263Info->curr_image, H263Info->curr_recon,
H263Info->lines, H263Info->pels);
#endif
/* PrintResult(H263Info->bits, 1, 1); */
/*
sv_H263FreeImage(H263Info->prev_image);
H263Info->prev_image=NULL;
sv_H263FreeImage(H263Info->prev_recon);
H263Info->prev_recon=NULL; HWG */
#if 0
if(H263Info->prefilter) {
int d;
for(d=0; d<H263_PYR_DEPTH; d++) sv_H263FreeImage(H263Info->curr_filtd[d]);
ScFree(H263Info->curr_filtd);
for(d=0; d<H263Info->mb_height; d++) ScFree(PreFilterLevel[d]);
ScFree(PreFilterLevel);
}
#endif
if (H263Info->extbitstream)
{
SvStatus_t status;
status = sv_H263WriteExtBitstream(H263Info, BSOut);
if (status!=SvErrorNone)
return(status);
}
/* point to next frame */
H263Info->frame_no += H263Info->distance_to_next_frame;
if (H263Info->frame_no>=H263Info->end) /* send an I frame */
return(sv_H263RefreshCompressor(Info));
return(SvErrorNone);
}
/*
** Purpose: Writes the RTP payload info out to the stream.
*/
static SvStatus_t sv_H263WriteExtBitstream(SvH263CompressInfo_t *H263Info,
ScBitstream_t *bs)
{
ScBSPosition_t pic_stop_position;
int i;
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
/* use this macro to byte reverse words */
#define PutBits32(BS, a) ScBSPutBits(BS, (a) & 0xff, 8); \
ScBSPutBits(BS, (a>>8)&0xff, 8); \
ScBSPutBits(BS, (a>>16)&0xff, 8); \
ScBSPutBits(BS, (a>>24)&0xff, 8);
pic_stop_position=ScBSBitPosition(bs);
/* round compressed size up to whole byte */
RTPInfo->trailer.dwCompressedSize=(dword)(((pic_stop_position-RTPInfo->pic_start_position)+7)/8);
/* Need to bitstuff here to make sure that these structures are DWORD aligned */
if ((pic_stop_position%32)!=0)
ScBSPutBits(bs, 0, 32-(unsigned int)(pic_stop_position % 32)); /* align on a DWORD boundary */
for (i = 0; i < (int)H263Info->RTPInfo->trailer.dwNumberOfPackets; i++)
{
ScBSPutBits(bs,0,32) ; /* Flags = 0 */
PutBits32(bs,RTPInfo->bsinfo[i].dwBitOffset);
ScBSPutBits(bs,RTPInfo->bsinfo[i].Mode,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].MBA,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].Quant,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].GOBN,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].HMV1,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].VMV1,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].HMV2,8);
ScBSPutBits(bs,RTPInfo->bsinfo[i].VMV2,8);
}
/* write RTP extension trailer */
PutBits32(bs, RTPInfo->trailer.dwVersion);
PutBits32(bs, RTPInfo->trailer.dwFlags);
PutBits32(bs, RTPInfo->trailer.dwUniqueCode);
PutBits32(bs, RTPInfo->trailer.dwCompressedSize);
PutBits32(bs, RTPInfo->trailer.dwNumberOfPackets);
ScBSPutBits(bs, RTPInfo->trailer.SourceFormat, 8);
ScBSPutBits(bs, RTPInfo->trailer.TR, 8);
ScBSPutBits(bs, RTPInfo->trailer.TRB, 8);
ScBSPutBits(bs, RTPInfo->trailer.DBQ, 8);
return (NoErrors);
}
/***************************************************/
/*
int start, int end, int source_format, int frameskip,
int ME_method, int headerlength, char *seqfilename,
int QP, int QPI, char *streamname, int unrestricted,
int sac, int advanced, int pb_frame, int bit_rate)
*/
/***************************************************/
SvStatus_t svH263InitCompressor(SvCodecInfo_t *Info)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
int i,j,k;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "sv_H263InitCompressor()") );
if (H263Info->inited)
return(SvErrorNone);
if (Info->Width==SQCIF_WIDTH && Info->Height==SQCIF_HEIGHT)
H263Info->source_format=H263_SF_SQCIF;
else if (Info->Width==QCIF_WIDTH && Info->Height==QCIF_HEIGHT)
H263Info->source_format=H263_SF_QCIF;
else if (Info->Width==CIF_WIDTH && Info->Height==CIF_HEIGHT)
H263Info->source_format=H263_SF_CIF;
else if (Info->Width==CIF4_WIDTH && Info->Height==CIF4_HEIGHT)
H263Info->source_format=H263_SF_4CIF;
else if (Info->Width==CIF16_WIDTH && Info->Height==CIF16_HEIGHT)
H263Info->source_format=H263_SF_16CIF;
else
{
_SlibDebug(_WARN_, ScDebugPrintf(H263Info->dbg, "sv_H263InitCompressor() Illegal input format\n") );
return(SvErrorUnrecognizedFormat);
}
/* start and stop frame numbers under to calculate rate control;
* a more advanced rate control is still needed
*/
H263Info->start = 0;
H263Info->pdist = H263Info->bdist = 1;
H263Info->first_loop_finished=0;
H263Info->PPFlag = 0;
H263Info->pic = (H263_Pict *)ScAlloc(sizeof(H263_Pict));
H263Info->bits = (H263_Bits *)ScAlloc(sizeof(H263_Bits));
H263Info->total_bits = (H263_Bits *)ScAlloc(sizeof(H263_Bits));
H263Info->intra_bits = (H263_Bits *)ScAlloc(sizeof(H263_Bits));
H263Info->res = (H263_Results *)ScAlloc(sizeof(H263_Results));
H263Info->total_res = (H263_Results *)ScAlloc(sizeof(H263_Results));
H263Info->b_res = (H263_Results *)ScAlloc(sizeof(H263_Results));
/* woring buffers */
H263Info->wk_buffers = ScAlloc(sizeof(H263_WORKING_BUFFER));
/*
fprintf(stdout,"\nH.263 coder (TMN)\n");
fprintf(stdout,"(C) Digital Equipment Corp.\n");
*/
H263Info->headerlength = H263_DEF_HEADERLENGTH;
H263Info->refidct = 0;
/* Initalize VLC_tables */
sv_H263InitHuff(H263Info);
/* allocate buffer for FAST search */
H263Info->block_subs2 = (unsigned char *)ScAlloc(sizeof(char)*64);
H263Info->srch_area_subs2=
(unsigned char *)ScAlloc(sizeof(char)*H263_SRCH_RANGE*H263_SRCH_RANGE);
if (H263Info->unrestricted){
/* note that the Unrestricted Motion Vector mode turns on
both long_vectors and mv_outside_frame */
H263Info->pic->unrestricted_mv_mode = H263Info->unrestricted;
H263Info->mv_outside_frame = H263_ON;
H263Info->long_vectors = H263_ON;
}
if (H263Info->advanced)
H263Info->mv_outside_frame = H263_ON;
/* H263Info->ME_method = ME_method; --- gets set in sv_api.c */
H263Info->HPME_method = H263_DEF_HPME_METHOD;
H263Info->DCT_method = H263_DEF_DCT_METHOD;
H263Info->vsnr = H263_DEF_VSNR;
#if 0
/*** prefilter ***/
H263Info->prefilter = H263_NO;
H263Info->PYR_DEPTH = H263_DEF_PYR_DEPTH;
H263Info->PrefPyrType = H263_DEF_PREF_PYR_TYPE;
H263Info->StaticPref = H263_DEF_STAT_PREF_STATE;
#endif
SetDefPrefLevel(H263Info);
SetDefThresh(H263Info);
/* BQUANT parameter for PB-frame coding
* (n * QP / 4 )
*
* BQUANT n
* 0 5
* 1 6
* 2 7
* 3 8
*/
H263Info->pic->BQUANT = 2;
if (H263Info->frame_rate<=1.0F) /* frame_rate not yet initialized */
H263Info->frame_rate = 30.0F;
H263Info->ref_frame_rate = H263Info->frame_rate;
H263Info->orig_frame_rate = H263Info->frame_rate;
/* default skipped frames between encoded frames (P or B) */
/* reference is original sequence */
/* 3 means 8.33/10.0 fps encoded frame rate with 25.0/30.0 fps original */
/* 1 means 8.33/10.0 fps encoded frame rate with 8.33/10.0 fps original */
H263Info->chosen_frameskip = 1;
/* default number of skipped frames in original sequence compared to */
/* the reference picture rate ( also option "-O <n>" ) */
/* 4 means that the original sequence is grabbed at 6.25/7.5 Hz */
/* 1 means that the original sequence is grabbed at 25.0/30.0 Hz */
H263Info->orig_frameskip = 1.0F;
H263Info->start_rate_control = 0;
H263Info->trace = H263_DEF_WRITE_TRACE;
H263Info->pic->seek_dist = H263_DEF_SEEK_DIST;
H263Info->pic->use_gobsync = H263_DEF_INSERT_SYNC;
/* define GOB sync */
H263Info->pic->use_gobsync = 1;
/* H263Info->bit_rate = bit_rate; --- gets set in sv_api.c */
/* default is variable bit rate (fixed quantizer) will be used */
H263Info->frames = 0;
H263Info->pframes = 0;
H263Info->bframes = 0;
H263Info->total_frames_passed = 0;
H263Info->pic->PB = 0;
H263Info->pic->TR = 0;
H263Info->QP = H263Info->QP_init;
H263Info->pic->QP_mean = (float)0.0;
_SlibDebug(_WARN_ && (H263Info->QP == 0 || H263Info->QPI == 0),
ScDebugPrintf(H263Info->dbg, "Warning: QP is zero. Bitstream will not be correctly decodable\n") );
_SlibDebug(_WARN_ && (H263Info->ref_frame_rate != 25.0 && H263Info->ref_frame_rate != 30.0),
ScDebugPrintf(H263Info->dbg, "Warning: Reference frame rate should be 25 or 30 fps\n") );
H263Info->pic->source_format = H263Info->source_format;
H263Info->pels = Info->Width;
H263Info->lines = Info->Height;
H263Info->PYR_DEPTH = H263Info->PYR_DEPTH>0 ? H263Info->PYR_DEPTH : 1;
H263Info->PYR_DEPTH = H263Info->PYR_DEPTH<=H263_MAX_PYR_DEPTH ? H263Info->PYR_DEPTH : H263_MAX_PYR_DEPTH;
CheckPrefLevel(H263Info, H263Info->PYR_DEPTH);
H263Info->cpels = H263Info->pels/2;
H263Info->mb_width = H263Info->pels / H263_MB_SIZE;
H263Info->mb_height = H263Info->lines / H263_MB_SIZE;
H263Info->orig_frameskip = H263Info->ref_frame_rate / H263Info->orig_frame_rate;
H263Info->frame_rate = H263Info->ref_frame_rate / (float)(H263Info->orig_frameskip * H263Info->chosen_frameskip);
_SlibDebug(_VERBOSE_,
ScDebugPrintf(H263Info->dbg, "Encoding frame rate : %.2f\n", H263Info->frame_rate);
ScDebugPrintf(H263Info->dbg, "Reference frame rate : %.2f\n", H263Info->ref_frame_rate);
ScDebugPrintf(H263Info->dbg, "Orig. seq. frame rate: %.2f\n\n",
H263Info->ref_frame_rate / (float)H263Info->orig_frameskip) );
if (H263Info->refidct) sv_H263init_idctref();
/* Open stream for writing */
/* svH263mwopen(H263Info->streamname); */
#if 0
/* open video sequence */
if ((H263Info->video_file = fopen(seqfilename,"rb")) == NULL) {
fprintf(stderr,"Unable to open image_file: %s\n",seqfilename);
exit(-1);
}
svH263RemovHead(H263Info->headerlength,start,H263Info->video_file);
#endif
/* for Motion Estimation */
for (j = 0; j < H263Info->mb_height+1; j++)
for (i = 0; i < H263Info->mb_width+2; i++)
for (k = 0; k < 6; k++)
H263Info->MV[k][j][i] = (H263_MotionVector *)ScAlloc(sizeof(H263_MotionVector));
/* for Interpolation */
if (H263Info->mv_outside_frame) {
if (H263Info->long_vectors)
H263Info->wk_buffers->ipol_image=(unsigned char *)ScAlloc(sizeof(char)*(H263Info->pels+64)*(H263Info->lines+64)*4);
else
H263Info->wk_buffers->ipol_image=(unsigned char *)ScAlloc(sizeof(char)*(H263Info->pels+32)*(H263Info->lines+32)*4);
}
else
H263Info->wk_buffers->ipol_image =(unsigned char *)ScAlloc(sizeof(char)*H263Info->pels*H263Info->lines*4);
if ((H263Info->wk_buffers->qcoeff_P=(short *)ScAlloc(sizeof(short)*384)) == 0)
return(SvErrorMemory);
/* allocate buffers for curr_image */
H263Info->curr_image = sv_H263InitImage(H263Info->pels*H263Info->lines);
if (H263Info->curr_image==NULL)
return(SvErrorMemory);
/* Point to the first frame to be coded */
H263Info->frame_no = H263Info->start;
/* initialization done */
H263Info->inited = TRUE;
H263Info->buffer_fullness = 0;
H263Info->buffer_frames_stored = 0;
if (H263Info->extbitstream)
{
H263Info->RTPInfo = (SvH263RTPInfo_t *) ScAlloc(sizeof(SvH263RTPInfo_t));
if (H263Info->RTPInfo==NULL)
return(SvErrorMemory);
memset(H263Info->RTPInfo, 0, sizeof(SvH263RTPInfo_t)) ;
}
#ifdef GOB_RATE_CONTROL
sv_H263GOBInitRateCntrl();
#endif
return(SvErrorNone);
}
/***************************************************/
/***************************************************/
SvStatus_t sv_H263RefreshCompressor(SvCodecInfo_t *Info)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
_SlibDebug(_VERBOSE_, ScDebugPrintf(H263Info->dbg, "Refresh Compressor()") );
if (!H263Info->inited)
return(SvErrorNone);
H263Info->pdist = H263Info->bdist = 1;
H263Info->first_loop_finished=0;
H263Info->PPFlag = 0;
H263Info->pic->BQUANT = 2;
H263Info->frames = 0;
H263Info->pframes = 0;
H263Info->bframes = 0;
H263Info->total_frames_passed = 0;
H263Info->pic->PB = 0;
H263Info->pic->TR = 0;
H263Info->QP = H263Info->QP_init;
H263Info->pic->QP_mean = (float)0.0;
/* Point to the first frame to be coded */
H263Info->frame_no = H263Info->start;
/* initialization done */
H263Info->inited = TRUE;
H263Info->buffer_fullness = 0;
H263Info->buffer_frames_stored = 0;
/* next frame will be key so we can reset bit positions */
ScBSResetCounters(Info->BSOut);
return(SvErrorNone);
}
/***************************************************/
/***************************************************/
void svH263FreeCompressor(SvCodecInfo_t *Info)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
int i,j,k;
_SlibDebug(_WRITE_, ScFileClose(DEBUGIMG) );
if (H263Info->inited)
{
/* Free memory */
for (j = 0; j < H263Info->mb_height+1; j++)
for (i = 0; i < H263Info->mb_width+2; i++)
for (k = 0; k < 6; k++)
ScFree(H263Info->MV[k][j][i]);
if (H263Info->block_subs2)
ScFree(H263Info->block_subs2);
if (H263Info->srch_area_subs2)
ScFree(H263Info->srch_area_subs2);
ScFree(H263Info->wk_buffers->qcoeff_P);
ScFree(H263Info->wk_buffers->ipol_image);
ScFree(H263Info->wk_buffers);
if (H263Info->curr_recon==H263Info->prev_recon ||
H263Info->curr_recon==H263Info->B_recon)
H263Info->curr_recon=NULL;
if (H263Info->prev_recon==H263Info->B_recon)
H263Info->prev_recon=NULL;
if (H263Info->curr_image==H263Info->prev_image ||
H263Info->curr_image==H263Info->B_image)
H263Info->curr_image=NULL;
if (H263Info->prev_image==H263Info->B_image)
H263Info->prev_image=NULL;
if (H263Info->curr_recon)
{
sv_H263FreeImage(H263Info->curr_recon);
H263Info->curr_recon=NULL;
}
if (H263Info->curr_image)
{
sv_H263FreeImage(H263Info->curr_image);
H263Info->curr_image=NULL;
}
if (H263Info->prev_recon)
{
sv_H263FreeImage(H263Info->prev_recon);
H263Info->prev_recon=NULL;
}
if (H263Info->prev_image)
{
sv_H263FreeImage(H263Info->prev_image);
H263Info->prev_image=NULL;
}
if (H263Info->B_image)
{
sv_H263FreeImage(H263Info->B_image);
H263Info->B_image=NULL;
}
if (H263Info->B_recon)
{
sv_H263FreeImage(H263Info->B_recon);
H263Info->B_recon=NULL;
}
sv_H263FreeHuff(H263Info);
ScFree(H263Info->bits);
ScFree(H263Info->total_bits);
ScFree(H263Info->intra_bits);
ScFree(H263Info->res);
ScFree(H263Info->total_res);
ScFree(H263Info->b_res);
ScFree(H263Info->pic);
H263Info->inited=FALSE;
if (H263Info->RTPInfo)
ScFree(H263Info->RTPInfo);
}
return;
}
/**********************************************************************
*
* Name: NextTwoPB
* Description: Decides whether or not to code the next
* two images as PB
* Speed: This is not a very smart solution considering
* the encoding speed, since motion vectors
* have to be calculation several times. It
* can be done together with the normal
* motion vector search, or a tree search
* instead of a full search can be used.
*
* Input: pointers to previous image, potential B-
* and P-image, frame distances
* Returns: 1 for yes, 0 otherwise
* Side effects:
*
***********************************************************************/
/* static int NextTwoPB(PictImage *next2, PictImage *next1, PictImage *prev,
int bskip, int pskip, int seek_dist) */
static int NextTwoPB(SvH263CompressInfo_t *H263Info,
H263_PictImage *next2, H263_PictImage *next1, H263_PictImage *prev,
int bskip, int pskip, int seek_dist)
{
int adv_is_on = 0, mof_is_on = 0, lv_is_on = 0;
int psad1, psad2, bsad, psad;
int x,y,i,j,tmp;
int ne2_pr_x, ne2_pr_y, mvbf_x, mvbf_y, mvbb_x, mvbb_y;
short MVx, MVy, MVer;
/* Temporarily disable some options to simplify motion estimation */
if (H263Info->advanced) {
H263Info->advanced = H263_OFF;
adv_is_on = H263_ON;
}
if (H263Info->mv_outside_frame) {
H263Info->mv_outside_frame = H263_OFF;
mof_is_on = H263_ON;
}
if (H263Info->long_vectors) {
H263Info->long_vectors = H263_OFF;
lv_is_on = H263_ON;
}
bsad = psad = psad1 = psad2 = 0;
/* Integer motion estimation */
for ( j = 1; j < H263Info->mb_height - 1; j++) {
for ( i = 1; i < H263Info->mb_width - 1 ; i++) {
x = i*H263_MB_SIZE;
y = j*H263_MB_SIZE;
/* picture order: prev -> next1 -> next2 */
/* next1 and next2 can be coded as PB or PP */
/* prev is the previous encoded picture */
/* computes vectors (prev <- next2) */
#if 1
/* faster estimation */
sv_H263FastME(H263Info, next2->lum,prev->lum,x,y,0,0,seek_dist,
&MVx,&MVy,&MVer,&tmp);
#else
svH263MotionEstimation(next2->lum,prev->lum,x,y,0,0,seek_dist,MV,&tmp);
#endif
/* not necessary to prefer zero vector here */
if (MVx == 0 && MVy == 0){
psad += (MVer + H263_PREF_NULL_VEC) ;
ne2_pr_x = ne2_pr_y = 0;
}
else{
psad += MVer ;
ne2_pr_x = MVx;
ne2_pr_y = MVy;
}
/* computes sad(prev <- next1) */
#if 1
/* faster estimation */
sv_H263FastME(H263Info, next1->lum,prev->lum,x,y,0,0,seek_dist,
&MVx,&MVy,&MVer,&tmp);
#else
svH263MotionEstimation(next1->lum,prev->lum,x,y,0,0,seek_dist,MV,&tmp);
#endif
if (MVx == 0 && MVy == 0)
psad2 += (MVer + H263_PREF_NULL_VEC);
else
psad2 += MVer;
/* computes vectors for (next1 <- next2) */
#if 1
/* faster estimation */
sv_H263FastME(H263Info, next2->lum,next1->lum,x,y,0,0,seek_dist,
&MVx,&MVy,&MVer,&tmp);
#else
svH263MotionEstimation(next2->lum,next1->lum,x,y,0,0,seek_dist,MV,&tmp);
#endif
if (MVx == 0 && MVy == 0)
psad1 += (MVer + H263_PREF_NULL_VEC);
else
psad1 += MVer ;
/* scales vectors for (prev <- next2 ) */
mvbf_x = bskip * ne2_pr_x / (bskip + pskip);
mvbb_x = - pskip * ne2_pr_x / (bskip + pskip);
mvbf_y = bskip * ne2_pr_y / (bskip + pskip);
mvbb_y = - pskip * ne2_pr_y / (bskip + pskip);
/* computes sad(prev <- next1 -> next2) */
#ifndef USE_C
bsad += sv_H263BError16x16_S(next1->lum + x + y*H263Info->pels,
next2->lum + x + mvbb_x + (y + mvbb_y)*H263Info->pels,
prev->lum + x + mvbf_x + (y + mvbf_y)*H263Info->pels,
H263Info->pels);
#else
bsad += sv_H263BError16x16_C(next1->lum + x + y*H263Info->pels,
next2->lum + x + mvbb_x + (y + mvbb_y)*H263Info->pels,
prev->lum + x + mvbf_x + (y + mvbf_y)*H263Info->pels,
H263Info->pels, INT_MAX);
#endif
}
}
/* restore advanced parameters */
H263Info->advanced = adv_is_on;
H263Info->mv_outside_frame = mof_is_on;
H263Info->long_vectors = lv_is_on;
/* do the decision */
if (bsad < (psad1+psad2)/2) {
/*
fprintf(stdout,"Chose PB - bsad %d, psad %d\n", bsad, (psad1+psad2)/2);
*/
return 1;
}
else {
/*
fprintf(stdout,"Chose PP - bsad %d, psad %d\n", bsad, (psad1+psad2)/2);
*/
return 0;
}
}
#ifdef _SLIBDEBUG_
/**********************************************************************
*
* Name: PrintResult
* Description: add bits and prints results
*
* Input: Bits struct
*
* Returns:
* Side effects:
*
***********************************************************************/
void PrintResult(SvH263CompressInfo_t *H263Info, H263_Bits *bits,
int num_units, int num)
{
ScDebugPrintf(H263Info->dbg,"# intra : %d\n", bits->no_intra/num_units);
ScDebugPrintf(H263Info->dbg,"# inter : %d\n", bits->no_inter/num_units);
ScDebugPrintf(H263Info->dbg,"# inter4v : %d\n", bits->no_inter4v/num_units);
ScDebugPrintf(H263Info->dbg,"--------------\n");
ScDebugPrintf(H263Info->dbg,"Coeff_Y: %d\n", bits->Y/num);
ScDebugPrintf(H263Info->dbg,"Coeff_C: %d\n", bits->C/num);
ScDebugPrintf(H263Info->dbg,"Vectors: %d\n", bits->vec/num);
ScDebugPrintf(H263Info->dbg,"CBPY : %d\n", bits->CBPY/num);
ScDebugPrintf(H263Info->dbg,"MCBPC : %d\n", bits->CBPCM/num);
ScDebugPrintf(H263Info->dbg,"MODB : %d\n", bits->MODB/num);
ScDebugPrintf(H263Info->dbg,"CBPB : %d\n", bits->CBPB/num);
ScDebugPrintf(H263Info->dbg,"COD : %d\n", bits->COD/num);
ScDebugPrintf(H263Info->dbg,"DQUANT : %d\n", bits->DQUANT/num);
ScDebugPrintf(H263Info->dbg,"header : %d\n", bits->header/num);
ScDebugPrintf(H263Info->dbg,"==============\n");
ScDebugPrintf(H263Info->dbg,"Total : %d\n", bits->total/num);
ScDebugPrintf(H263Info->dbg,"\n");
return;
}
#endif
/*****************************************************************
*
* coder.c for H.263 encoder
* Wei-Lien Hsu
* Date: December 11, 1996
*
*****************************************************************/
static void SelectBounds(H263_PictImage *Img, unsigned char **PL, int rows, int cols) ;
static unsigned char LargeMv(H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int th) ;
static unsigned char LargePerror(H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int th);
static unsigned char BoundaryMB(SvH263CompressInfo_t *H263Info, int i, int j, int pels, int lines) ;
static int GetPrefLevel(SvH263CompressInfo_t *H263Info, H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int rows, int cols) ;
void FillLumBlock(SvH263CompressInfo_t *H263Info, int x, int y, H263_PictImage *image, H263_MB_Structure *data);
void FillChromBlock(SvH263CompressInfo_t *H263Info, int x_curr, int y_curr, H263_PictImage *image,
H263_MB_Structure *data);
void FillLumPredBlock(SvH263CompressInfo_t *H263Info, int x, int y, PredImage *image, H263_MB_Structure *data);
void FillChromPredBlock(SvH263CompressInfo_t *H263Info, int x_curr, int y_curr, PredImage *image,
H263_MB_Structure *data);
void ZeroMBlock(H263_MB_Structure *data);
void ReconImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, H263_PictImage *recon);
void ReconPredImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, PredImage *recon);
void InterpolateImage(unsigned char *image, unsigned char *ipol_image,
int width, int height);
void MotionEstimatePicture(SvH263CompressInfo_t *H263Info, unsigned char *curr, unsigned char *prev,
unsigned char *prev_ipol, int seek_dist,
H263_MotionVector *MV[5][H263_MBR+1][H263_MBC+2], int gobsync);
void MakeEdgeImage(unsigned char *src, unsigned char *dst, int width,
int height, int edge);
/**************************************************************************
* Function: SelectBounds
* Draws a boundary around each MacroBlock with width equal to its assigned
* prefilter level
*************************************************************************/
#if 0
void SelectBounds(H263_PictImage *Img, unsigned char **PL, int rows, int cols)
{
int i, j, l, m, n, r, c;
for(i=0; i<rows/H263_MB_SIZE; i++) {
for(j=0; j<cols/H263_MB_SIZE; j++) {
for(l=0; l<PL[i][j]; l++) {
r = i*H263_MB_SIZE+l;
for(n=l; n<H263_MB_SIZE-l; n++) {
c = j*H263_MB_SIZE+n;
Img->lum[r*cols+c] = 255;
Img->lum[(r+H263_MB_SIZE-1-l)*cols+c] = 255;
}
c = j*H263_MB_SIZE+l;
for(m=l; m<H263_MB_SIZE-l; m++) {
r = i*H263_MB_SIZE+m;
Img->lum[r*cols+c] = 255;
Img->lum[r*cols+(c+H263_MB_SIZE-1-l)] = 255;
}
}
}
}
}
#endif
/**********************************************************************
* Function: LargeMv
* Checks if the norm of the integer component of the motion vector
* of the macroblock i, j is largen than the threshold th. Returns 1 if
* yes, 0 if not.
* Added by Nuno on 07/1/96 to support adaptive prefiltering.
**********************************************************************/
unsigned char LargeMv(H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int th)
{
return(sqrt((double) MV[0][j+1][i+1]->x*MV[0][j+1][i+1]->x +
(double) MV[0][j+1][i+1]->y*MV[0][j+1][i+1]->y) > th);
}
/**********************************************************************
* Function: LargePerror
* Checks if the prediction error for macroblock i, j is largen than
* the threshold th. Returns 1 if yes, 0 if not.
* Added by Nuno on 07/1/96 to support adaptive prefiltering.
**********************************************************************/
unsigned char LargePerror(H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int th)
{
return(MV[0][j+1][i+1]->min_error > th);
}
/**********************************************************************
* Function: BoundaryMB
* Returns 1 if a MB is on the boundary of the image, o if not.
* Added by Nuno on 07/1/96 to support adaptive prefiltering.
**********************************************************************/
unsigned char BoundaryMB(SvH263CompressInfo_t *H263Info, int i, int j, int pels, int lines)
{
return(j==0 || i==0 || i==(H263Info->mb_width -1) || j==(H263Info->mb_height - 1));
}
/***********************************************************************
* Function: GetPrefLevel
* Selects the level of the pyramid of prefiltered images that is best
* suited for the encoding of the MacroBlock (i,j)
**********************************************************************/
int GetPrefLevel(SvH263CompressInfo_t *H263Info,
H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int i, int j, int rows, int cols)
{
int motbin, pebin;
motbin = 0;
while(LargeMv(MV, i, j, (int) H263Info->MOTresh[motbin]) && motbin<3) motbin++;
pebin = 0;
while(LargePerror(MV, i, j, H263Info->PETresh[pebin]) && pebin<2) pebin++;
if(BoundaryMB(H263Info, i, j, cols, rows) && motbin<3) motbin++;
return H263Info->PREF_LEVEL[motbin][pebin];
}
/**********************************************************************
*
* Name: sv_H263CodeOneOrTwo
* Description: code one image normally or two images
* as a PB-frame (CodeTwoPB and CodeOnePred merged)
*
* Input: pointer to image, prev_image, prev_recon, Q
*
* Returns: pointer to reconstructed image
* Side effects: memory is allocated to recon image
* changed by Nuno on 06/27/96 to support filtering of the prediction error
***********************************************************************/
static SvStatus_t sv_H263CodeOneOrTwo(SvCodecInfo_t *Info, int QP, int frameskip,
H263_Bits *bits, H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2])
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
ScBitstream_t *BSOut = Info->BSOut;
H263_Pict *pic=H263Info->pic;
unsigned char *prev_ipol,*pi_edge=NULL,*orig_lum;
H263_MotionVector ZERO = {0,0,0,0,0};
H263_PictImage *prev_recon=NULL, *pr_edge=NULL;
H263_MB_Structure *recon_data_P = (H263_MB_Structure *)ScAlloc(sizeof(H263_MB_Structure));
H263_MB_Structure *recon_data_B=NULL;
H263_MB_Structure *diff=(H263_MB_Structure *)ScAlloc(sizeof(H263_MB_Structure));
H263_MB_Structure *Bpred=NULL;
short *qcoeff_P;
short *qcoeff_B=NULL;
unsigned char *pi;
int Mode,B;
int CBP, CBPB=0;
int bquant[] = {5,6,7,8};
int QP_B;
int newgob;
int i,j,k;
/* buffer control vars */
float QP_cumulative = (float)0.0;
int abs_mb_num = 0, QuantChangePostponed = 0;
int QP_new, QP_prev, dquant, QP_xmitted=QP;
sv_H263ZeroBits(bits);
pi = H263Info->wk_buffers->ipol_image;
qcoeff_P= H263Info->wk_buffers->qcoeff_P;
if(pic->PB){
if ((qcoeff_B=(short *)ScAlloc(sizeof(short)*384)) == 0)
return(SvErrorMemory);
recon_data_B=(H263_MB_Structure *)ScAlloc(sizeof(H263_MB_Structure));
Bpred=(H263_MB_Structure *)ScAlloc(sizeof(H263_MB_Structure));
}
/* interpolate image */
if (H263Info->mv_outside_frame) {
if (H263Info->long_vectors) {
/* If the Extended Motion Vector range is used, motion vectors
may point further out of the picture than in the normal range,
and the edge images will have to be made larger */
B = 16;
}
else {
/* normal range */
B = 8;
}
pi_edge = (unsigned char *)ScAlloc(sizeof(char)*(H263Info->pels+4*B)*(H263Info->lines+4*B));
if (pi_edge == NULL)
return(SvErrorMemory);
MakeEdgeImage(H263Info->prev_recon->lum,pi_edge + (H263Info->pels + 4*B)*2*B+2*B,H263Info->pels,H263Info->lines,2*B);
InterpolateImage(pi_edge, pi, H263Info->pels+4*B, H263Info->lines+4*B);
ScFree(pi_edge);
prev_ipol = pi + (2*H263Info->pels + 8*B) * 4*B + 4*B;
/* luma of non_interpolated image */
pr_edge = sv_H263InitImage((H263Info->pels+4*B)*(H263Info->lines+4*B));
MakeEdgeImage(H263Info->prev_image->lum, pr_edge->lum + (H263Info->pels + 4*B)*2*B+2*B,
H263Info->pels,H263Info->lines,2*B);
orig_lum = pr_edge->lum + (H263Info->pels + 4*B)*2*B+2*B;
/* non-interpolated image */
MakeEdgeImage(H263Info->prev_recon->lum,pr_edge->lum + (H263Info->pels+4*B)*2*B + 2*B,H263Info->pels,H263Info->lines,2*B);
MakeEdgeImage(H263Info->prev_recon->Cr,pr_edge->Cr + (H263Info->pels/2 + 2*B)*B + B,H263Info->pels/2,H263Info->lines/2,B);
MakeEdgeImage(H263Info->prev_recon->Cb,pr_edge->Cb + (H263Info->pels/2 + 2*B)*B + B,H263Info->pels/2,H263Info->lines/2,B);
prev_recon = (H263_PictImage *)ScAlloc(sizeof(H263_PictImage));
prev_recon->lum = pr_edge->lum + (H263Info->pels + 4*B)*2*B + 2*B;
prev_recon->Cr = pr_edge->Cr + (H263Info->pels/2 + 2*B)*B + B;
prev_recon->Cb = pr_edge->Cb + (H263Info->pels/2 + 2*B)*B + B;
}
else {
InterpolateImage(H263Info->prev_recon->lum,pi,H263Info->pels,H263Info->lines);
prev_ipol = pi;
prev_recon = H263Info->prev_recon;
orig_lum = H263Info->prev_image->lum;
}
/* mark PMV's outside the frame */
for (i = 1; i < H263Info->mb_width+1; i++) {
for (k = 0; k < 6; k++) {
sv_H263MarkVec(MV[k][0][i]);
}
MV[0][0][i]->Mode = H263_MODE_INTRA;
}
/* zero out PMV's outside the frame */
for (i = 0; i < H263Info->mb_height+1; i++) {
for (k = 0; k < 6; k++) {
sv_H263ZeroVec(MV[k][i][0]);
sv_H263ZeroVec(MV[k][i][H263Info->mb_width+1]);
}
MV[0][i][0]->Mode = H263_MODE_INTRA;
MV[0][i][H263Info->mb_width+1]->Mode = H263_MODE_INTRA;
}
/* Integer and half pel motion estimation */
MotionEstimatePicture(H263Info, H263Info->curr_image->lum,prev_recon->lum,prev_ipol,
pic->seek_dist,MV, pic->use_gobsync);
/*
fprintf(stdout,"\nMotion Vector Magintudes\n");
for ( j = 0; j < H263Info->lines/H263_MB_SIZE; j++) {
for ( i = 0; i < H263Info->pels/H263_MB_SIZE; i++) {
fprintf(stdout, "%4.0lf ", sqrt((double) MV[0][j+1][i+1]->x*MV[0][j+1][i+1]->x
+ MV[0][j+1][i+1]->y*MV[0][j+1][i+1]->y));
}
fprintf(stdout,"\n");
}
fprintf(stdout,"\nMacroBlock Prediction Error\n");
for ( j = 0; j < H263Info->lines/H263_MB_SIZE; j++) {
for ( i = 0; i < H263Info->pels/H263_MB_SIZE; i++) {
fprintf(stdout, "%4d ", MV[0][j+1][i+1]->min_error);
}
fprintf(stdout,"\n");
}
*/
/* note: integer pel motion estimation is now based on previous
reconstructed image, not the previous original image. We have
found that this works better for some sequences and not worse for
others. Note that it can not easily be changed back by
substituting prev_recon->lum with orig_lum in the line above,
because SAD for zero vector is not re-calculated in the half
pel search. The half pel search has always been based on the
previous reconstructed image */
#ifdef GOB_RATE_CONTROL
if (H263Info->bit_rate != 0) {
/* Initialization routine for Rate Control */
QP_new = sv_H263GOBInitQP((float)H263Info->bit_rate,
(pic->PB ? H263Info->frame_rate/2 : H263Info->frame_rate),
pic->QP_mean);
QP_xmitted = QP_prev = QP_new;
}
else {
QP_new = QP_xmitted = QP_prev = QP; /* Copy the passed value of QP */
}
#else
QP_new = QP_prev = QP; /* Copy the passed value of QP */
#endif
dquant = 0;
/* TRAILER information */
if (H263Info->extbitstream)
{
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
RTPInfo->trailer.dwVersion = 0;
RTPInfo->trailer.dwFlags = 0;
if(H263Info->syntax_arith_coding)
RTPInfo->trailer.dwFlags |= RTP_H263_SAC;
if(H263Info->advanced)
RTPInfo->trailer.dwFlags |= RTP_H263_AP;
if(H263Info->pb_frames)
H263Info->RTPInfo->trailer.dwFlags |= RTP_H263_PB_FRAME;
RTPInfo->trailer.dwUniqueCode = BI_DECH263DIB;
RTPInfo->trailer.dwNumberOfPackets = 1;
RTPInfo->trailer.SourceFormat = (unsigned char)H263Info->source_format;
RTPInfo->trailer.TR = (unsigned char)pic->TR;
RTPInfo->trailer.TRB = (unsigned char)pic->TRB;
RTPInfo->trailer.DBQ = (unsigned char)pic->BQUANT;
RTPInfo->pre_MB_position = RTPInfo->pre_GOB_position
= RTPInfo->pic_start_position = RTPInfo->packet_start_position
= ScBSBitPosition(BSOut); /* HWG - added pre_MB and pre_GOB */
RTPInfo->packet_id = 0 ;
RTPInfo->bsinfo[0].dwBitOffset = 0 ;
RTPInfo->bsinfo[0].Mode = H263_RTP_MODE_A;
RTPInfo->pic_start_position = ScBSBitPosition(BSOut);
}
for ( j = 0; j < H263Info->mb_height; j++)
{
/* If a rate control scheme which updates the quantizer for each
slice is used, it should be added here like this: */
#ifdef GOB_RATE_CONTROL
if (H263Info->bit_rate != 0) {
/* QP updated at the beginning of each row */
sv_H263AddBitsPicture(H263Info->bits);
QP_new = sv_H263GOBUpdateQP(abs_mb_num, pic->QP_mean,
(float)H263Info->bit_rate, H263Info->pels/H263_MB_SIZE,
H263Info->lines/H263_MB_SIZE, H263Info->bits->total,j,VARgob,
pic->PB);
}
#endif
/* In other words: you have to set QP_new with some function, not
necessarily called UpdateQuantizer. Check the source code for
version 1.5 if you would like to see how it can be done. Read the
comment in ratectrl.c to see why we removed this scheme. You mau
also have to add initializer functions before and after the
encoding of each frame. Special care has to be taken for the intra
frame if you are designing a system for fixed bitrate and small
delay.
If you calculate QP_new here, the rest of the code in the main
loop will support this.
If you think the TMN5 scheme worked well enough for you, and the
simplified scheme is too simple, you can easily add the TMN5 code
back. However, this will not work with the adaptive PB-frames at
all! */
newgob = 0;
if (j == 0) {
pic->QUANT = QP_new;
bits->header += sv_H263CountBitsPicture(H263Info, BSOut, pic);
QP_xmitted = QP_prev = QP_new;
}
else if (pic->use_gobsync && j%pic->use_gobsync == 0) {
/* insert gob sync */
bits->header += sv_H263CountBitsSlice(H263Info, BSOut, j,QP_new);
QP_xmitted = QP_prev = QP_new;
newgob = 1;
}
for ( i = 0; i < H263Info->mb_width; i++) {
/* Update of dquant, check and correct its limit */
dquant = QP_new - QP_prev;
if (dquant != 0 && i != 0 && MV[0][j+1][i+1]->Mode == H263_MODE_INTER4V) {
/* It is not possible to change the quantizer and at the same
time use 8x8 vectors. Turning off 8x8 vectors is not
possible at this stage because the previous macroblock
encoded assumed this one should use 8x8 vectors. Therefore
the change of quantizer is postponed until the first MB
without 8x8 vectors */
dquant = 0;
QP_xmitted = QP_prev;
QuantChangePostponed = 1;
}
else {
QP_xmitted = QP_new;
QuantChangePostponed = 0;
}
if (dquant > 2) { dquant = 2; QP_xmitted = QP_prev + dquant;}
if (dquant < -2) { dquant = -2; QP_xmitted = QP_prev + dquant;}
pic->DQUANT = dquant;
/* modify mode if dquant != 0 (e.g. MODE_INTER -> MODE_INTER_Q) */
Mode = sv_H263ModifyMode(MV[0][j+1][i+1]->Mode,pic->DQUANT);
MV[0][j+1][i+1]->Mode = (short)Mode;
pic->MB = i + j * H263Info->mb_width;
if (Mode == H263_MODE_INTER || Mode == H263_MODE_INTER_Q || Mode==H263_MODE_INTER4V) {
/* Predict P-MB */
if (H263Info->prefilter) {
H263Info->PreFilterLevel[j][i] = (unsigned char)GetPrefLevel(H263Info, MV, i, j, H263Info->lines, H263Info->pels);
sv_H263PredictP(H263Info, H263Info->curr_filtd[H263Info->PreFilterLevel[j][i]],prev_recon,prev_ipol,
i*H263_MB_SIZE,j*H263_MB_SIZE,MV,pic->PB,diff);
}
else
sv_H263PredictP(H263Info, H263Info->curr_image,prev_recon,prev_ipol, i*H263_MB_SIZE,
j*H263_MB_SIZE,MV,pic->PB,diff);
}
else {
if (H263Info->prefilter) {
H263Info->PreFilterLevel[j][i] = (unsigned char)GetPrefLevel(H263Info, MV, i, j, H263Info->lines, H263Info->pels);
FillLumBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, H263Info->curr_filtd[H263Info->PreFilterLevel[j][i]], diff);
FillChromBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, H263Info->curr_filtd[H263Info->PreFilterLevel[j][i]], diff);
}
else {
FillLumBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, H263Info->curr_image, diff);
FillChromBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, H263Info->curr_image, diff);
}
}
/* P or INTRA Macroblock DCT + Quantization and IQuant+IDCT*/
sv_H263MBEncode(diff, QP_xmitted, Mode, &CBP, qcoeff_P, H263Info->calc_quality);
if (CBP == 0 && (Mode == H263_MODE_INTER || Mode == H263_MODE_INTER_Q))
ZeroMBlock(diff);
else sv_H263MBDecode(H263Info, qcoeff_P, diff, QP_xmitted, Mode, CBP, H263Info->calc_quality);
sv_H263MBReconP(H263Info, prev_recon, prev_ipol,diff,
i*H263_MB_SIZE,j*H263_MB_SIZE,MV,pic->PB,recon_data_P);
sv_H263Clip(recon_data_P);
/* Predict B-MB using reconstructed P-MB and prev. recon. image */
if (pic->PB) {
if (H263Info->prefilter) {
H263Info->PreFilterLevel[j][i] = (unsigned char)GetPrefLevel(H263Info, MV, i, j, H263Info->lines, H263Info->pels);
sv_H263PredictB(H263Info, H263Info->B_filtd[H263Info->PreFilterLevel[j][i]],
prev_recon, prev_ipol,i*H263_MB_SIZE,
j*H263_MB_SIZE, MV, recon_data_P, frameskip, pic->TRB,
diff, Bpred);
}
else sv_H263PredictB(H263Info, H263Info->B_image, prev_recon, prev_ipol,
i*H263_MB_SIZE, j*H263_MB_SIZE,
MV, recon_data_P, frameskip, pic->TRB,
diff, Bpred);
if (QP_xmitted == 0) QP_B = 0; /* (QP = 0 means no quantization) */
else QP_B = mmax(1,mmin(31,bquant[pic->BQUANT]*QP_xmitted/4));
sv_H263MBEncode(diff, QP_B, H263_MODE_INTER, &CBPB, qcoeff_B, H263Info->calc_quality);
if(H263Info->vsnr) { /* reconstruction only for performance measurement */
if (CBPB) sv_H263MBDecode(H263Info, qcoeff_B, diff, QP_B, H263_MODE_INTER, CBP, H263Info->calc_quality);
else ZeroMBlock(diff);
sv_H263MBReconB(H263Info, prev_recon, diff,prev_ipol,
i*H263_MB_SIZE, j*H263_MB_SIZE,MV,recon_data_P,
frameskip, pic->TRB, recon_data_B, Bpred);
sv_H263Clip(recon_data_B);
}
/* decide MODB */
if (CBPB) pic->MODB = H263_PBMODE_CBPB_MVDB;
else {
if (MV[5][j+1][i+1]->x == 0 && MV[5][j+1][i+1]->y == 0)
pic->MODB = H263_PBMODE_NORMAL;
else pic->MODB = H263_PBMODE_MVDB;
}
}
else
sv_H263ZeroVec(MV[5][j+1][i+1]); /* Zero out PB deltas */
/* Entropy coding */
if ((CBP==0) && (CBPB==0) && (sv_H263EqualVec(MV[0][j+1][i+1],&ZERO)) &&
(sv_H263EqualVec(MV[5][j+1][i+1],&ZERO)) &&
(Mode == H263_MODE_INTER || Mode == H263_MODE_INTER_Q)) {
/* Skipped MB : both CBP and CBPB are zero, 16x16 vector is zero,
PB delta vector is zero and Mode = MODE_INTER */
if (Mode == H263_MODE_INTER_Q) {
/* DQUANT != 0 but not coded anyway */
QP_xmitted = QP_prev;
pic->DQUANT = 0;
Mode = H263_MODE_INTER;
}
if (!H263Info->syntax_arith_coding)
sv_H263CountBitsMB(BSOut, Mode,1,CBP,CBPB,pic,bits);
else
sv_H263CountSACBitsMB(H263Info, BSOut, Mode,1,CBP,CBPB,pic,bits);
}
else { /* Normal MB */
if (!H263Info->syntax_arith_coding) { /* VLC */
sv_H263CountBitsMB(BSOut, Mode,0,CBP,CBPB,pic,bits);
if (Mode == H263_MODE_INTER || Mode == H263_MODE_INTER_Q) {
bits->no_inter++;
sv_H263CountBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
else if (Mode == H263_MODE_INTER4V) {
bits->no_inter4v++;
sv_H263CountBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
else {
/* MODE_INTRA or MODE_INTRA_Q */
bits->no_intra++;
if (pic->PB)
sv_H263CountBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
if (CBP || Mode == H263_MODE_INTRA || Mode == H263_MODE_INTRA_Q)
sv_H263CountBitsCoeff(BSOut, qcoeff_P, Mode, CBP, bits, 64);
if (CBPB)
sv_H263CountBitsCoeff(BSOut, qcoeff_B, H263_MODE_INTER, CBPB, bits, 64);
} /* end VLC */
else { /* SAC */
sv_H263CountSACBitsMB(H263Info, BSOut, Mode,0,CBP,CBPB,pic,bits);
if (Mode == H263_MODE_INTER || Mode == H263_MODE_INTER_Q) {
bits->no_inter++;
sv_H263CountSACBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
else if (Mode == H263_MODE_INTER4V) {
bits->no_inter4v++;
sv_H263CountSACBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
else {
/* MODE_INTRA or MODE_INTRA_Q */
bits->no_intra++;
if (pic->PB)
sv_H263CountSACBitsVectors(H263Info, BSOut, MV, bits, i, j, Mode, newgob, pic);
}
if (CBP || Mode == H263_MODE_INTRA || Mode == H263_MODE_INTRA_Q)
sv_H263CountSACBitsCoeff(H263Info, BSOut, qcoeff_P, Mode, CBP, bits, 64);
if (CBPB)
sv_H263CountSACBitsCoeff(H263Info, BSOut, qcoeff_B, H263_MODE_INTER, CBPB, bits, 64);
} /* end SAC */
QP_prev = QP_xmitted;
} /* End Normal Block */
abs_mb_num++;
QP_cumulative += QP_xmitted;
#ifdef PRINTQ
/* most useful when quantizer changes within a picture */
if (QuantChangePostponed) fprintf(stdout,"@%2d",QP_xmitted);
else fprintf(stdout," %2d",QP_xmitted);
#endif
if (pic->PB && H263Info->vsnr)
ReconImage(H263Info, i,j,recon_data_B,H263Info->B_recon);
ReconImage(H263Info, i,j,recon_data_P,H263Info->curr_recon);
if ((H263Info->extbitstream&PARAM_FORMATEXT_RTPB)!=0)
{
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
ScBSPosition_t cur_position = ScBSBitPosition(BSOut);
/* start a new packet */
if((cur_position - RTPInfo->packet_start_position) >= H263Info->packetsize)
{
SvH263BSInfo_t *RTPBSInfo=&RTPInfo->bsinfo[RTPInfo->packet_id];
if (RTPInfo->pre_MB_position>RTPBSInfo->dwBitOffset)
{
RTPBSInfo++; RTPInfo->packet_id++;
RTPInfo->trailer.dwNumberOfPackets++;
}
RTPBSInfo->dwBitOffset = (unsigned dword)H263Info->RTPInfo->packet_start_position;
RTPInfo->packet_start_position = RTPInfo->pre_MB_position;
RTPBSInfo->Mode = H263_RTP_MODE_B;
RTPBSInfo->Quant = (unsigned char)QP_xmitted;
RTPBSInfo->GOBN = (unsigned char)j;
if(Mode==H263_MODE_INTER4V) {
RTPBSInfo->HMV1 = (char)MV[1][j+1][i+1]->x;
RTPBSInfo->VMV1 = (char)MV[1][j+1][i+1]->y;
RTPBSInfo->HMV2 = (char)MV[2][j+1][i+1]->x;
RTPBSInfo->VMV2 = (char)MV[2][j+1][i+1]->y;
}
else {
RTPBSInfo->HMV1 = (char)MV[0][j+1][i+1]->x;
RTPBSInfo->VMV1 = (char)MV[0][j+1][i+1]->y;
RTPBSInfo->HMV2 = 0;
RTPBSInfo->VMV2 = 0;
}
}
RTPInfo->pre_MB_position = cur_position;
}
} /* end of line of blocks - j loop */
if ((H263Info->extbitstream&PARAM_FORMATEXT_RTPA)!=0)
{
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
ScBSPosition_t cur_position = ScBSBitPosition(BSOut);
/* start a new packet */
if((cur_position - RTPInfo->packet_start_position) >= H263Info->packetsize)
{
SvH263BSInfo_t *RTPBSInfo=&RTPInfo->bsinfo[RTPInfo->packet_id];
if (RTPInfo->pre_GOB_position>RTPBSInfo->dwBitOffset)
{
RTPBSInfo++; RTPInfo->packet_id++;
RTPInfo->trailer.dwNumberOfPackets++;
}
RTPInfo->packet_start_position = RTPInfo->pre_GOB_position;
RTPBSInfo->dwBitOffset = (unsigned dword)RTPInfo->packet_start_position;
RTPBSInfo->Mode = H263_RTP_MODE_A;
}
RTPInfo->pre_GOB_position = cur_position;
}
#ifdef PRINTQ
fprintf(stdout,"\n");
#endif
} /* end of image - i loop */
pic->QP_mean = QP_cumulative/(float)abs_mb_num;
/* Free memory */
ScFree(diff);
ScFree(recon_data_P);
if (pic->PB) {
ScFree(recon_data_B);
ScFree(Bpred);
}
if (H263Info->mv_outside_frame)
{
ScFree(prev_recon);
sv_H263FreeImage(pr_edge);
}
if(pic->PB) ScFree(qcoeff_B);
return(SvErrorNone);
}
/**********************************************************************
*
* Name: CodeOneIntra
* Description: codes one image intra
*
* Input: pointer to image, QP
*
* Returns: pointer to reconstructed image
* Side effects: memory is allocated to recon image
*
***********************************************************************/
H263_PictImage *sv_H263CodeOneIntra(SvCodecInfo_t *Info, H263_PictImage *curr,
H263_PictImage *recon, int QP, H263_Bits *bits, H263_Pict *pic)
{
SvH263CompressInfo_t *H263Info = Info->h263comp;
ScBitstream_t *BSOut=Info->BSOut;
H263_MB_Structure *data = (H263_MB_Structure *)ScAlloc(sizeof(H263_MB_Structure));
short *qcoeff;
int Mode = H263_MODE_INTRA;
int CBP,COD;
int i,j;
if ((qcoeff=(short *)ScAlloc(sizeof(short)*384)) == 0) {
_SlibDebug(_WARN_, ScDebugPrintf(H263Info->dbg, "mb_encode(): Couldn't allocate qcoeff.\n") );
return(NULL);
}
/* TRAILER information */
if (H263Info->extbitstream)
{
/* H263Info->RTPInfo->trailer.dwSrcVersion = 0; */
H263Info->RTPInfo->trailer.dwVersion = 0;
H263Info->RTPInfo->trailer.dwFlags = RTP_H263_INTRA_CODED;
if(H263Info->syntax_arith_coding)
H263Info->RTPInfo->trailer.dwFlags |= RTP_H263_SAC;
if(H263Info->advanced)
H263Info->RTPInfo->trailer.dwFlags |= RTP_H263_AP;
if(H263Info->pb_frames)
H263Info->RTPInfo->trailer.dwFlags |= RTP_H263_PB_FRAME;
H263Info->RTPInfo->trailer.dwUniqueCode = BI_DECH263DIB;
H263Info->RTPInfo->trailer.dwNumberOfPackets = 1;
H263Info->RTPInfo->trailer.SourceFormat = (unsigned char)H263Info->source_format;
H263Info->RTPInfo->trailer.TR = 0;
H263Info->RTPInfo->trailer.TRB = 0;
H263Info->RTPInfo->trailer.DBQ = 0;
H263Info->RTPInfo->pre_GOB_position = H263Info->RTPInfo->pre_MB_position
= H263Info->RTPInfo->pic_start_position
= H263Info->RTPInfo->packet_start_position = ScBSBitPosition(BSOut);
H263Info->RTPInfo->packet_id = 0 ;
H263Info->RTPInfo->bsinfo[0].dwBitOffset = 0 ;
H263Info->RTPInfo->bsinfo[0].Mode = H263_RTP_MODE_A;
}
sv_H263ZeroBits(bits);
pic->QUANT = QP;
bits->header += sv_H263CountBitsPicture(H263Info, BSOut, pic);
COD = 0; /* Every block is coded in Intra frame */
for ( j = 0; j < H263Info->mb_height; j++) {
/* insert sync in *every* slice if use_gobsync is chosen */
if (pic->use_gobsync && j != 0)
bits->header += sv_H263CountBitsSlice(H263Info, BSOut, j,QP);
for ( i = 0; i < H263Info->mb_width; i++) {
pic->MB = i + j * H263Info->mb_width;
bits->no_intra++;
FillLumBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, curr, data);
FillChromBlock(H263Info, i*H263_MB_SIZE, j*H263_MB_SIZE, curr, data);
sv_H263MBEncode(data, QP, Mode, &CBP, qcoeff, H263Info->calc_quality);
if (!H263Info->syntax_arith_coding) {
sv_H263CountBitsMB(BSOut, Mode,COD,CBP,0,pic,bits);
sv_H263CountBitsCoeff(BSOut, qcoeff, Mode, CBP,bits,64);
} else {
sv_H263CountSACBitsMB(H263Info, BSOut, Mode,COD,CBP,0,pic,bits);
sv_H263CountSACBitsCoeff(H263Info, BSOut, qcoeff, Mode, CBP,bits,64);
}
sv_H263MBDecode(H263Info, qcoeff, data, QP, Mode, CBP, H263Info->calc_quality);
sv_H263Clip(data);
ReconImage(H263Info, i,j,data,recon);
if ((H263Info->extbitstream&PARAM_FORMATEXT_RTPB)!=0)
{
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
ScBSPosition_t cur_position = ScBSBitPosition(BSOut);
/* start a new packet */
if((cur_position - RTPInfo->packet_start_position) >= H263Info->packetsize)
{
SvH263BSInfo_t *RTPBSInfo=&RTPInfo->bsinfo[RTPInfo->packet_id];
if (RTPInfo->pre_MB_position>RTPBSInfo->dwBitOffset)
{
RTPBSInfo++; RTPInfo->packet_id++;
RTPInfo->trailer.dwNumberOfPackets++;
}
RTPInfo->packet_start_position = RTPInfo->pre_MB_position;
RTPBSInfo->dwBitOffset = (unsigned dword)RTPInfo->packet_start_position;
RTPBSInfo->Mode = H263_RTP_MODE_B;
RTPBSInfo->Quant = (unsigned char)QP;
RTPBSInfo->GOBN = (unsigned char)j;
RTPBSInfo->HMV1 = 0;
RTPBSInfo->VMV1 = 0;
RTPBSInfo->HMV2 = 0;
RTPBSInfo->VMV2 = 0;
}
RTPInfo->pre_MB_position = cur_position;
}
}
if ((H263Info->extbitstream&PARAM_FORMATEXT_RTPA)!=0)
{
SvH263RTPInfo_t *RTPInfo=H263Info->RTPInfo;
ScBSPosition_t cur_position = ScBSBitPosition(BSOut);
/* start a new packet */
if((cur_position - RTPInfo->packet_start_position) >= H263Info->packetsize)
{
SvH263BSInfo_t *RTPBSInfo=&RTPInfo->bsinfo[RTPInfo->packet_id];
if (RTPInfo->pre_GOB_position>RTPBSInfo->dwBitOffset)
{
RTPBSInfo++; RTPInfo->packet_id++;
RTPInfo->trailer.dwNumberOfPackets++;
}
RTPInfo->packet_start_position = RTPInfo->pre_GOB_position;
RTPBSInfo->dwBitOffset = (unsigned dword)RTPInfo->packet_start_position;
RTPBSInfo->Mode = H263_RTP_MODE_A;
}
RTPInfo->pre_GOB_position = cur_position;
}
}
pic->QP_mean = (float)QP;
ScFree(data);
ScFree(qcoeff);
return recon;
}
/**********************************************************************
*
* Name: MB_Encode
* Description: DCT and quantization of Macroblocks
*
* Input: MB data struct, mquant (1-31, 0 = no quant),
* MB info struct
* Returns: Pointer to quantized coefficients
* Side effects:
*
**********************************************************************/
static int sv_H263MBEncode(H263_MB_Structure *mb_orig, int QP, int I, int *CBP,
short *qcoeff, unsigned dword quality)
{
int i, k, l, row, blkid;
short fblock[64];
short *coeff_ind;
coeff_ind = qcoeff;
*CBP = 0;
blkid = 0;
for (k=0;k<16;k+=8) {
for (l=0;l<16;l+=8) {
for (i=k,row=0;row<64;i++,row+=8)
memcpy(fblock + row, &(mb_orig->lum[i][l]), 16) ;
#if 1
/* DCT in ZZ order */
if(quality > 40){
if(sv_H263DCT(fblock,coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I)) *CBP |= (32 >> blkid);
}
else {
if(sv_H263ZoneDCT(fblock,coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I)) *CBP |= (32 >> blkid);
}
#else
switch (DCT_method) {
case(H263_DCT16COEFF):
svH263Dct16coeff(fblock,coeff_ind);
break;
case(H263_DCT4BY4):
svH263Dct4by4(fblock,coeff_ind);
break;
}
if(sv_H263Quant(coeff_ind,QP,I) != 0) *CBP |= (32 >> blkid);
#endif
coeff_ind += 64;
blkid++;
}
}
#if 1
/* DCT in ZZ order */
if(quality > 40){
if(sv_H263DCT(&(mb_orig->Cb[0][0]),coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I)) *CBP |= (32 >> blkid);
}
else {
if(sv_H263ZoneDCT(&(mb_orig->Cb[0][0]),coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I)) *CBP |= (32 >> blkid);
}
#else
memcpy(&fblock[0], &(mb_orig->Cb[0][0]), 128);
switch (DCT_method) {
case(H263_DCT16COEFF):
svH263Dct16coeff(fblock,coeff_ind);
break;
case(H263_DCT4BY4):
svH263Dct4by4(fblock,coeff_ind);
break;
}
if(sv_H263Quant(coeff_ind,QP,I) != 0) *CBP |= (32 >> blkid);
#endif
coeff_ind += 64;
blkid++;
#if 1
/* DCT in ZZ order */
if(quality > 40){
if(sv_H263DCT( &(mb_orig->Cr[0][0]),coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I) != 0) *CBP |= (32 >> blkid);
}
else {
if(sv_H263ZoneDCT( &(mb_orig->Cr[0][0]),coeff_ind,QP,I))
if(sv_H263Quant(coeff_ind,QP,I) != 0) *CBP |= (32 >> blkid);
}
#else
memcpy(&fblock[0], &(mb_orig->Cr[0][0]),128);
switch (DCT_method) {
case(H263_DCT16COEFF):
svH263Dct16coeff(fblock,coeff_ind);
break;
case(H263_DCT4BY4):
svH263Dct4by4(fblock,coeff_ind);
break;
}
if(sv_H263Quant(coeff_ind,QP,I) != 0) *CBP |= (32 >> blkid);
#endif
return 1;
}
/**********************************************************************
*
* Name: MB_Decode
* Description: Reconstruction of quantized DCT-coded Macroblocks
*
* Input: Quantized coefficients, MB data
* QP (1-31, 0 = no quant), MB info block
* Returns: int (just 0)
* Side effects:
*
**********************************************************************/
/* de-quantization */
static short sv_H263MBDecode(SvH263CompressInfo_t *H263Info, short *qcoeff,
H263_MB_Structure *mb_recon, int QP, int I, int CBP,
unsigned dword quality)
{
int i, k, l, row, blkid;
short *iblock;
short *qcoeff_ind;
short *rcoeff, *rcoeff_ind;
if(H263Info->refidct) {
if ((rcoeff = (short *)ScAlloc(sizeof(short)*64)) == NULL) {
_SlibDebug(_WARN_, ScDebugPrintf(H263Info->dbg, "sv_H263MBDecode() Could not allocate space for rcoeff\n") );
return(0);
}
if ((iblock = (short *)ScAlloc(sizeof(short)*64)) == NULL) {
_SlibDebug(_WARN_, ScDebugPrintf(H263Info->dbg, "sv_H263MBDecode() Could not allocate space for iblock\n") );
return(0);
}
}
/* Zero data into lum-Cr-Cb, For control purposes */
memset(&(mb_recon->lum[0][0]), 0 , 768) ;
qcoeff_ind = qcoeff;
blkid = 0;
for (k=0;k<16;k+=8) {
for (l=0;l<16;l+=8) {
if((CBP & (32 >> blkid)) || I == H263_MODE_INTRA || I == H263_MODE_INTRA_Q)
{
if (H263Info->refidct) {
rcoeff_ind = rcoeff;
sv_H263Dequant(qcoeff_ind,rcoeff_ind,QP,I);
sv_H263idctref(rcoeff_ind,iblock);
for (i=k,row=0;row<64;i++,row+=8)
memcpy(&(mb_recon->lum[i][l]), iblock+row, 16) ;
}
else /* IDCT with ZZ and quantization */
{
if(quality > 40)
sv_H263IDCT(qcoeff_ind,&(mb_recon->lum[k][l]),QP,I,16);
else
sv_H263ZoneIDCT(qcoeff_ind,&(mb_recon->lum[k][l]),QP,I,16);
}
}
else {
for (i=k,row=0;row<64;i++,row+=8)
memset(&(mb_recon->lum[i][l]), 0, 16) ;
}
qcoeff_ind += 64;
blkid++;
}
}
if((CBP & (32 >> blkid)) || I == H263_MODE_INTRA || I == H263_MODE_INTRA_Q)
{
if (H263Info->refidct){
sv_H263Dequant(qcoeff_ind,rcoeff_ind,QP,I);
sv_H263idctref(rcoeff_ind,&(mb_recon->Cb[0][0]));
}
else /* IDCT with ZZ and quantization */
{
if(quality > 40)
sv_H263IDCT(qcoeff_ind,&(mb_recon->Cb[0][0]),QP,I,8);
else
sv_H263ZoneIDCT(qcoeff_ind,&(mb_recon->Cb[0][0]),QP,I,8);
}
}
blkid++ ;
qcoeff_ind += 64;
if((CBP & (32 >> blkid)) || I == H263_MODE_INTRA || I == H263_MODE_INTRA_Q) {
if (H263Info->refidct) {
sv_H263Dequant(qcoeff_ind,rcoeff_ind,QP,I);
sv_H263idctref(rcoeff_ind,&(mb_recon->Cr[0][0]));
}
else /* IDCT with ZZ and quantization */
{
if(quality > 40)
sv_H263IDCT(qcoeff_ind,&(mb_recon->Cr[0][0]),QP,I,8);
else
sv_H263ZoneIDCT(qcoeff_ind,&(mb_recon->Cr[0][0]),QP,I,8);
}
}
if (H263Info->refidct){
ScFree(rcoeff);
ScFree(iblock);
}
return 0;
}
/**********************************************************************
*
* Name: FillLumBlock
* Description: Fills the luminance of one block of PictImage
*
* Input: Position, pointer to PictImage, array to fill
* Returns:
* Side effects: fills array
*
***********************************************************************/
#ifndef USE_C
void FillLumBlock(SvH263CompressInfo_t *H263Info,
int x, int y, H263_PictImage *image, H263_MB_Structure *data)
{
sv_H263FilLumBlk_S((image->lum + x + y*H263Info->pels), &(data->lum[0][0]), H263Info->pels);
return;
}
#else
void FillLumBlock(SvH263CompressInfo_t *H263Info,
int x, int y, H263_PictImage *image, H263_MB_Structure *data)
{
int n, m, off;
register short *ptnb;
unsigned char *ptna ;
ptna = image->lum + x + y*H263Info->pels ;
ptnb = &(data->lum[0][0]) ;
off = H263Info->pels - H263_MB_SIZE;
for (n = 0; n < H263_MB_SIZE; n++){
for (m = 0; m < H263_MB_SIZE; m++)
*(ptnb++) = (short) *(ptna++) ;
ptna += off;
}
return;
}
#endif
/**********************************************************************
*
* Name: FillChromBlock
* Description: Fills the chrominance of one block of PictImage
*
* Input: Position, pointer to PictImage, array to fill
* Returns:
* Side effects: fills array
* 128 subtracted from each
*
***********************************************************************/
#ifndef USE_C
void FillChromBlock(SvH263CompressInfo_t *H263Info, int x_curr, int y_curr, H263_PictImage *image,
H263_MB_Structure *data)
{
int off;
off = (x_curr>>1) + (y_curr>>1)* H263Info->cpels;
sv_H263FilChmBlk_S(image->Cr + off, &(data->Cr[0][0]),
image->Cb + off, &(data->Cb[0][0]), H263Info->cpels) ;
return;
}
#else
void FillChromBlock(SvH263CompressInfo_t *H263Info, int x_curr, int y_curr, H263_PictImage *image,
H263_MB_Structure *data)
{
register int m, n;
int off;
short *ptnb, *ptnd;
unsigned char *ptna, *ptnc;
off = (x_curr>>1) + (y_curr>>1)* H263Info->cpels;
ptna = image->Cr + off; ptnb = &(data->Cr[0][0]) ;
ptnc = image->Cb + off; ptnd = &(data->Cb[0][0]) ;
off = H263Info->cpels - 8 ;
for (n = 0; n < 8; n++){
for (m = 0; m < 8; m++) {
*(ptnb++) = (short)*(ptna++);
*(ptnd++) = (short)*(ptnc++);
}
ptna += off;
ptnc += off;
}
return;
}
#endif
/**********************************************************************
*
* Name: FillLumPredBlock
* Description: Fills the luminance of one block of PredImage
*
* Input: Position, pointer to PredImage, array to fill
* Returns:
* Side effects: fills array
*
***********************************************************************/
#if 1
void FillLumPredBlock(SvH263CompressInfo_t *H263Info, int x, int y, PredImage *image,
H263_MB_Structure *data)
{
int n;
register short *ptna, *ptnb;
ptna = image->lum + x + y*H263Info->pels ;
ptnb = &(data->lum[0][0]) ;
for (n = 0; n < H263_MB_SIZE; n++){
memcpy(ptnb,ptna,32);
ptnb+=16 ; ptna += H263Info->pels ;
}
return;
}
#else
void FillLumPredBlock(SvH263CompressInfo_t *H263Info, int x, int y, PredImage *image, H263_MB_Structure *data)
{
int n;
register int m;
for (n = 0; n < H263_MB_SIZE; n++)
for (m = 0; m < H263_MB_SIZE; m++)
data->lum[n][m] = *(image->lum + x+m + (y+n)*H263Info->pels);
return;
}
#endif
/**********************************************************************
*
* Name: FillChromPredBlock
* Description: Fills the chrominance of one block of PictImage
*
* Input: Position, pointer to PictImage, array to fill
* Returns:
* Side effects: fills array
* 128 subtracted from each
*
* Added by Nuno on 06/27/96 to support filtering of the prediction error
***********************************************************************/
#if 1
void FillChromPredBlock(SvH263CompressInfo_t *H263Info, int x_curr, int y_curr, PredImage *image,
H263_MB_Structure *data)
{
int n, off;
register short *ptna, *ptnb, *ptnc, *ptnd ;
off = (x_curr>>1) + (y_curr>>1)* H263Info->cpels;
ptna = image->Cr + off; ptnb = &(data->Cr[0][0]) ;
ptnc = image->Cb + off; ptnd = &(data->Cb[0][0]) ;
for (n = 0; n < 8; n++){
memcpy(ptnb,ptna,16);
ptnb+=8 ; ptna += H263Info->cpels ;
memcpy(ptnd,ptnc,16);
ptnd+=8 ; ptnc += H263Info->cpels ;
}
return;
}
#else
void FillChromPredBlock(SvH263CompressInfo_t *H263Info,
int x_curr, int y_curr, PredImage *image,
H263_MB_Structure *data)
{
int n;
register int m;
int x, y;
x = x_curr>>1;
y = y_curr>>1;
for (n = 0; n < (H263_MB_SIZE>>1); n++)
for (m = 0; m < (H263_MB_SIZE>>1); m++) {
data->Cr[n][m] = *(image->Cr +x+m + (y+n)*H263Info->cpels);
data->Cb[n][m] = *(image->Cb +x+m + (y+n)*H263Info->cpels);
}
return;
}
#endif
/**********************************************************************
*
* Name: ZeroMBlock
* Description: Fills one MB with Zeros
*
* Input: MB_Structure to zero out
* Returns:
* Side effects:
*
***********************************************************************/
#if 1
void ZeroMBlock(H263_MB_Structure *data)
{
memset(&(data->lum[0][0]), 0, 768) ;
return;
}
#else
void ZeroMBlock(H263_MB_Structure *data)
{
int n;
register int m;
for (n = 0; n < H263_MB_SIZE; n++)
for (m = 0; m < H263_MB_SIZE; m++)
data->lum[n][m] = 0;
for (n = 0; n < (H263_MB_SIZE>>1); n++)
for (m = 0; m < (H263_MB_SIZE>>1); m++) {
data->Cr[n][m] = 0;
data->Cb[n][m] = 0;
}
return;
}
#endif
/**********************************************************************
*
* Name: ReconImage
* Description: Puts together reconstructed image
*
* Input: position of curr block, reconstructed
* macroblock, pointer to recontructed image
* Returns:
* Side effects:
*
***********************************************************************/
#ifndef USE_C
void ReconImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, H263_PictImage *recon)
{
unsigned char *ptna, *ptnb;
int x_curr, y_curr;
x_curr = i * H263_MB_SIZE;
y_curr = j * H263_MB_SIZE;
/* Fill in luminance data */
ptna = recon->lum + x_curr + y_curr*H263Info->pels;
sv_H263ItoC16A_S(&(data->lum[0][0]), ptna, H263Info->pels) ;
/* Fill in chrominance data */
ptna = recon->Cr + (x_curr>>1) + (y_curr>>1)*H263Info->cpels;
ptnb = recon->Cb + (x_curr>>1) + (y_curr>>1)*H263Info->cpels;
sv_H263ItoC8B_S(&(data->Cr[0][0]), ptna, &(data->Cb[0][0]), ptnb, H263Info->pels/2) ;
return;
}
#else
void ReconImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, H263_PictImage *recon)
{
int n;
register int m;
int x_curr, y_curr;
x_curr = i * H263_MB_SIZE;
y_curr = j * H263_MB_SIZE;
/* Fill in luminance data */
for (n = 0; n < H263_MB_SIZE; n++)
for (m= 0; m < H263_MB_SIZE; m++) {
*(recon->lum + x_curr+m + (y_curr+n)*H263Info->pels) = (unsigned char)data->lum[n][m];
}
/* Fill in chrominance data */
for (n = 0; n < H263_MB_SIZE>>1; n++)
for (m = 0; m < H263_MB_SIZE>>1; m++) {
*(recon->Cr + (x_curr>>1)+m + ((y_curr>>1)+n)*H263Info->cpels) = (unsigned char) data->Cr[n][m];
*(recon->Cb + (x_curr>>1)+m + ((y_curr>>1)+n)*H263Info->cpels) = (unsigned char) data->Cb[n][m];
}
return;
}
#endif
/**********************************************************************
*
* Name: ReconPredImage
* Description: Puts together prediction error image
*
* Input: position of curr block, reconstructed
* macroblock, pointer to recontructed image
* Returns:
* Side effects:
*
* Added by Nuno on 06/27/96 to support filtering of the prediction error
***********************************************************************/
#if 1
void ReconPredImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, PredImage *recon)
{
int n;
int x_curr, y_curr;
register short *pta, *ptb, *ptc, *ptd;
x_curr = i * H263_MB_SIZE;
y_curr = j * H263_MB_SIZE;
/* Fill in luminance data */
pta = recon->lum + x_curr + y_curr * H263Info->pels ;
ptb = &(data->lum[0][0]) ;
for (n = 0; n < H263_MB_SIZE; n++){
memcpy(ptb,pta,32);
ptb+=H263_MB_SIZE ; pta += H263Info->pels ;
}
/* Fill in chrominance data */
pta = recon->Cr + (x_curr>>1) + (y_curr>>1)*H263Info->cpels ;
ptb = recon->Cb + (x_curr>>1) + (y_curr>>1)*H263Info->cpels ;
ptc = &(data->Cr[0][0]) ;
ptd = &(data->Cb[0][0]) ;
for (n = 0; n < H263_MB_SIZE>>1; n++){
memcpy(ptc,pta,16);
memcpy(ptd,ptb,16);
pta += H263Info->cpels; ptc+=H263_MB_SIZE;
ptb += H263Info->cpels; ptd+=H263_MB_SIZE;
}
return;
}
#else
void ReconPredImage(SvH263CompressInfo_t *H263Info, int i, int j, H263_MB_Structure *data, PredImage *recon)
{
int n;
register int m;
int x_curr, y_curr;
x_curr = i * H263_MB_SIZE;
y_curr = j * H263_MB_SIZE;
/* Fill in luminance data */
for (n = 0; n < H263_MB_SIZE; n++)
for (m= 0; m < H263_MB_SIZE; m++) {
*(recon->lum + x_curr+ m + (y_curr + n)*H263Info->pels) = data->lum[n][m];
}
/* Fill in chrominance data */
for (n = 0; n < H263_MB_SIZE>>1; n++)
for (m = 0; m < H263_MB_SIZE>>1; m++) {
*(recon->Cr + (x_curr>>1)+m + ((y_curr>>1)+n)*H263Info->cpels) = data->Cr[n][m];
*(recon->Cb + (x_curr>>1)+m + ((y_curr>>1)+n)*H263Info->cpels) = data->Cb[n][m];
}
return;
}
#endif
/**********************************************************************
*
* Name: InterpolateImage
* Description: Interpolates a complete image for easier half
* pel prediction
*
* Input: pointer to image structure
* Returns: pointer to interpolated image
* Side effects: allocates memory to interpolated image
*
***********************************************************************/
void InterpolateImage(unsigned char *image, unsigned char *ipol_image,
int width, int height)
{
register unsigned char *ii, *oo, *ij, *oi;
int i,j,w2,w4,w1;
unsigned char tmp1;
#ifdef USE_C
unsigned char tmp2, tmp3;
#endif
ii = ipol_image;
oo = image;
w2 = (width<<1);
w4 = (width<<2);
w1 = width - 1;
/* main image */
#ifndef USE_C
for (j = 0; j < height-1; j++) {
sv_H263Intrpolt_S(oo, ii, oo + width, ii + w2, width) ;
ii += w4 ;
oo += width;
}
#else
for (j = 0; j < height-1; j++) {
oi = oo; ij = ii;
for (i = 0; i < width-1; i++, ij+=2, oi++) {
*(ij) = (tmp1 = *oi);
*(ij + 1) = (tmp1 + (tmp2 = *(oi + 1)) + 1)>>1;
*(ij + w2) = (tmp1 + (tmp3 = *(oi + width)) + 1)>>1;
*(ij + 1 + w2) = (tmp1 + tmp2 + tmp3 + *(oi+1+width) + 2)>>2;
}
/* last pels on each line */
*(ii+ w2 -2) = *(ii+ w2 -1) = *(oo + w1);
*(ii+ w4 -2) = *(ii+ w4 -1) = (*(oo+w1) + *(oo+width+w1) + 1)>>1;
ii += w4 ;
oo += width;
}
#endif
/* last lines */
ij = ii; oi = oo;
for (i=0; i < width-1; i++, ij+=2, oi++) {
*ij = *(ij+ w2) = (tmp1 = *oi );
*(ij + 1) = *(ij+ w2 + 1) = (tmp1 + *(oi + 1) + 1)>>1;
}
/* bottom right corner pels */
*(ii+w2-2)= *(ii+w2-1) = *(ii+w4-2) = *(ii+w4-1) = *(oo+w1);
return ;
}
/**********************************************************************
*
* Name: MotionEstimatePicture
* Description: Finds integer and half pel motion estimation
* and chooses 8x8 or 16x16
*
* Input: current image, previous image, interpolated
* reconstructed previous image, seek_dist,
* motion vector array
* Returns:
* Side effects: allocates memory for MV structure
*
***********************************************************************/
void MotionEstimatePicture(SvH263CompressInfo_t *H263Info, unsigned char *curr, unsigned char *prev,
unsigned char *prev_ipol, int seek_dist,
H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int gobsync)
{
int i,j,k;
int pmv0,pmv1,xoff,yoff;
int sad8 = INT_MAX, sad16, sad0;
int newgob;
H263_MotionVector *f0,*f1,*f2,*f3,*f4;
int VARmb;
void (*MotionEst_Func)(SvH263CompressInfo_t *H263Info,
unsigned char *curr, unsigned char *prev,
int x_curr, int y_curr, int xoff, int yoff, int seek_dist,
H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int *SAD_0);
switch(H263Info->ME_method) {
default:
case(H263_FULL_SEARCH):
MotionEst_Func = sv_H263MotionEstimation;
break;
case(H263_TWO_LEVELS_7_1):
MotionEst_Func = sv_H263ME_2levels_7_1;
break;
case(H263_TWO_LEVELS_421_1):
MotionEst_Func = sv_H263ME_2levels_421_1;
break;
case(H263_TWO_LEVELS_7_polint):
MotionEst_Func = sv_H263ME_2levels_7_polint;
break;
case(H263_TWO_LEVELS_7_pihp):
MotionEst_Func = sv_H263ME_2levels_7_pihp;
break;
}
/* Do motion estimation and store result in array */
for ( j = 0; j < H263Info->mb_height; j++) {
newgob = 0;
if (gobsync && j%gobsync == 0) newgob = 1;
H263Info->VARgob[j] = 0;
for ( i = 0; i < H263Info->mb_width; i++) {
/* Integer pel search */
f0 = MV[0][j+1][i+1];
f1 = MV[1][j+1][i+1];
f2 = MV[2][j+1][i+1];
f3 = MV[3][j+1][i+1];
f4 = MV[4][j+1][i+1];
/* NBNB need to use newgob properly as last parameter */
sv_H263FindPMV(MV,i+1,j+1,&pmv0,&pmv1,0,newgob,0);
/* Here the PMV's are found using integer motion vectors */
/* (NB should add explanation for this )*/
if (H263Info->long_vectors) {
xoff = pmv0/2; /* always divisable by two */
yoff = pmv1/2;
}
else xoff = yoff = 0;
MotionEst_Func(H263Info, curr, prev, i*H263_MB_SIZE, j*H263_MB_SIZE,
xoff, yoff, seek_dist, MV, &sad0);
sad16 = f0->min_error;
if (H263Info->advanced)
sad8 = f1->min_error + f2->min_error + f3->min_error + f4->min_error;
f0->Mode = (short)sv_H263ChooseMode(H263Info, curr,i*H263_MB_SIZE,j*H263_MB_SIZE,
mmin(sad8,sad16), &VARmb);
H263Info->VARgob[j] += VARmb;
/* Half pel search */
if (f0->Mode != H263_MODE_INTRA) {
if(H263Info->advanced) {
#ifndef USE_C
/* performance Half-Pel Motion Search on 8x8 blocks */
sv_H263AdvHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f0,f1,f2,f3,f4,prev_ipol,curr,16,0);
#else
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f0, prev_ipol, curr, 16, 0);
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f1, prev_ipol, curr, 8, 0);
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f2, prev_ipol, curr, 8, 1);
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f3, prev_ipol, curr, 8, 2);
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f4, prev_ipol, curr, 8, 3);
#endif
sad16 = f0->min_error;
sad8 = f1->min_error +f2->min_error +f3->min_error +f4->min_error;
sad8 += H263_PREF_16_VEC;
/* Choose Zero Vector, 8x8 or 16x16 vectors */
if (sad0 < sad8 && sad0 < sad16) {
f0->x = f0->y = 0;
f0->x_half = f0->y_half = 0;
}
else { if (sad8 < sad16) f0->Mode = H263_MODE_INTER4V; }
}
else {
/* performance Half-Pel Motion Search on 16 x 16 blocks */
sv_H263FindHalfPel(H263Info, i*H263_MB_SIZE,j*H263_MB_SIZE,f0, prev_ipol, curr, 16, 0);
sad16 = f0->min_error;
/* Choose Zero Vector or 16x16 vectors */
if (sad0 < sad16) {
f0->x = f0->y = 0;
f0->x_half = f0->y_half = 0;
}
}
}
else for (k = 0; k < 5; k++) sv_H263ZeroVec(MV[k][j+1][i+1]);
}
H263Info->VARgob[j] /= (H263Info->mb_width);
}
#ifdef PRINTMV
fprintf(stdout,"Motion estimation\n");
fprintf(stdout,"16x16 vectors:\n");
for ( j = 0; j < H263Info->mb_height; j++) {
for ( i = 0; i < H263Info->pels/H263_MB_SIZE; i++) {
if (MV[0][j+1][i+1]->Mode != H263_MODE_INTRA)
fprintf(stdout," %3d%3d",
2*MV[0][j+1][i+1]->x + MV[0][j+1][i+1]->x_half,
2*MV[0][j+1][i+1]->y + MV[0][j+1][i+1]->y_half);
else
fprintf(stdout," . . ");
}
fprintf(stdout,"\n");
}
if (H263Info->advanced) {
fprintf(stdout,"8x8 vectors:\n");
for (k = 1; k < 5; k++) {
fprintf(stdout,"Block: %d\n", k-1);
for ( j = 0; j < H263Info->lines/H263_MB_SIZE; j++) {
for ( i = 0; i < H263Info->pels/H263_MB_SIZE; i++) {
if (MV[0][j+1][i+1]->Mode != H263_MODE_INTRA)
fprintf(stdout," %3d%3d",
2*MV[k][j+1][i+1]->x + MV[k][j+1][i+1]->x_half,
2*MV[k][j+1][i+1]->y + MV[k][j+1][i+1]->y_half);
else
fprintf(stdout," . . ");
}
fprintf(stdout,"\n");
}
}
}
#endif
return;
}
/**********************************************************************
*
* Name: MakeEdgeImage
* Description: Copies edge pels for use with unrestricted
* motion vector mode
*
* Input: pointer to source image, destination image
* width, height, edge
* Returns:
* Side effects:
*
***********************************************************************/
void MakeEdgeImage(unsigned char *src, unsigned char *dst, int width,
int height, int edge)
{
int j;
unsigned char *p1,*p2,*p3,*p4;
unsigned char *o1,*o2,*o3,*o4;
int off, off1, off2;
unsigned char t1, t2, t3, t4 ;
/* center image */
p1 = dst;
o1 = src;
off = (edge<<1);
for (j = 0; j < height;j++) {
memcpy(p1,o1,width);
p1 += width + off;
o1 += width;
}
/* left and right edges */
p1 = dst-1;
o1 = src;
off1 = width + 1 ; off2 = width - 1 ;
for (j = 0; j < height;j++) {
t1 = *o1 ; t2 = *(o1 + off2);
memset(p1-edge+1,t1,edge);
memset(p1+off1,t2,edge);
p1 += width + off;
o1 += width;
}
/* top and bottom edges */
p1 = dst;
p2 = dst + (width + (edge<<1))*(height-1);
o1 = src;
o2 = src + width*(height-1);
off = width + (edge<<1) ;
for (j = 0; j < edge;j++) {
p1 -= off;
p2 += off;
memcpy(p1,o1,width);
memcpy(p2,o2,width);
}
/* corners */
p1 = dst - (width+(edge<<1)) - 1;
p2 = p1 + width + 1;
p3 = dst + (width+(edge<<1))*(height)-1;
p4 = p3 + width + 1;
o1 = src;
o2 = o1 + width - 1;
o3 = src + width*(height-1);
o4 = o3 + width - 1;
t1 = *o1; t2 = *o2; t3 = *o3; t4 = *o4;
for (j = 0; j < edge; j++) {
memset(p1-edge+1,t1,edge);
memset(p2,t2,edge);
memset(p3-edge+1,t3,edge);
memset(p4,t4,edge);
p1 -= off;
p2 -= off;
p3 += off;
p4 += off;
}
}
/**********************************************************************
*
* Name: Clip
* Description: clips recontructed data 0-255
*
* Input: pointer to recon. data structure
* Side effects: data structure clipped
*
***********************************************************************/
void sv_H263Clip(H263_MB_Structure *data)
{
#ifdef USE_C
int m,n;
for (n = 0; n < 16; n++) {
for (m = 0; m < 16; m++) {
data->lum[n][m] = mmin(255,mmax(0,data->lum[n][m]));
}
}
for (n = 0; n < 8; n++) {
for (m = 0; m < 8; m++) {
data->Cr[n][m] = mmin(255,mmax(0,data->Cr[n][m]));
data->Cb[n][m] = mmin(255,mmax(0,data->Cb[n][m]));
}
}
#else
sv_H263Clp_S(&(data->lum[0][0]), 16);
sv_H263Clp_S(&(data->Cr[0][0]), 4);
sv_H263Clp_S(&(data->Cb[0][0]), 4);
#endif
}
#ifdef _SLIBDEBUG_
/**********************************************************************
*
* Description: calculate SNR
*
***********************************************************************/
static int frame_id=0;
static float avg_SNR_l=0.0F, avg_SNR_Cr=0.0F, avg_SNR_Cb=0.0F;
void ComputeSNR(SvH263CompressInfo_t *H263Info,
H263_PictImage *im1, H263_PictImage *im2,
int lines, int pels)
{
int n;
register int m;
int quad, quad_Cr, quad_Cb, diff;
float SNR_l, SNR_Cr, SNR_Cb;
#if _WRITE_
if (!frame_id) DEBUGIMG = ScFileOpenForWriting("DEBUG.IMG", TRUE);
#endif
quad = 0;
quad_Cr = quad_Cb = 0;
/* Luminance */
quad = 0;
for (n = 0; n < lines; n++)
for (m = 0; m < pels; m++) {
diff = *(im1->lum + m + n*pels) - *(im2->lum + m + n*pels);
quad += diff * diff;
}
SNR_l = (float)quad/(float)(pels*lines);
if (SNR_l) {
SNR_l = (float)(255*255) / SNR_l;
SNR_l = (float)(10 * log10(SNR_l));
}
else SNR_l = (float) 99.99;
ScDebugPrintf(H263Info->dbg, "\n Frame %d : SNR of LUM = %f",frame_id++,SNR_l);
/* Chrominance */
for (n = 0; n < lines/2; n++)
for (m = 0; m < pels/2; m++) {
quad_Cr += (*(im1->Cr+m + n*pels/2) - *(im2->Cr + m + n*pels/2)) *
(*(im1->Cr+m + n*pels/2) - *(im2->Cr + m + n*pels/2));
quad_Cb += (*(im1->Cb+m + n*pels/2) - *(im2->Cb + m + n*pels/2)) *
(*(im1->Cb+m + n*pels/2) - *(im2->Cb + m + n*pels/2));
}
SNR_Cr = (float)quad_Cr/(float)(pels*lines/4);
if (SNR_Cr) {
SNR_Cr = (float)(255*255) / SNR_Cr;
SNR_Cr = (float)(10 * log10(SNR_Cr));
}
else SNR_Cr = (float) 99.99;
SNR_Cb = (float)quad_Cb/(float)(pels*lines/4);
if (SNR_Cb) {
SNR_Cb = (float)(255*255) / SNR_Cb;
SNR_Cb = (float)(10 * log10(SNR_Cb));
}
else SNR_Cb = (float)99.99;
ScDebugPrintf(H263Info->dbg, "SNR of Cr = %f Cb = %f \n",SNR_Cr, SNR_Cb);
avg_SNR_l += SNR_l;
avg_SNR_Cb += SNR_Cb;
avg_SNR_Cr += SNR_Cr;
ScDebugPrintf(H263Info->dbg, "AVG_SNR: lum %f Cr %f Cb %f\n",
avg_SNR_l/(float)frame_id,
avg_SNR_Cr/(float)frame_id,
avg_SNR_Cb/(float)frame_id);
#if _WRITE_
ScFileWrite(DEBUGIMG, im1->lum, pels*lines);
ScFileWrite(DEBUGIMG, im1->Cb, pels*lines/4);
ScFileWrite(DEBUGIMG, im1->Cr, pels*lines/4);
#endif
return;
}
#endif /* _SLIBDEBUG_ */