www.pudn.com > MPlayer-1.0pre8.rar > divx4_vbr.c


/*
 *  divx4_vbr.c
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License. See the file COPYING in the main directory of the Linux
 *  distribution for more details.
 *
 *  2-pass code OpenDivX port:
 *  Copyright (C) 2001 Christoph Lampert  
 *
 *  Large parts of this code were taken from VbrControl() from the OpenDivX
 *  project, (C) divxnetworks, written by Eugene Kuznetsov 
 *  with the permission of Darrius "Junto" Thompson, Director DivX
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "divx4_vbr.h"

#include "mp_msg.h"
#include "help_mp.h"

//#include "transcode.h"

#define FALSE 0
#define TRUE 1

/*  Absolute maximum and minimum quantizers used in VBR modes */
static const int min_quantizer=1;
static const int max_quantizer=31;

/*  Limits on frame-level deviation of quantizer ( higher values
	correspond to frames with more changes and vice versa ) */	
static const float min_quant_delta=-10.f;
static const float max_quant_delta=5.f;
/*  Limits on stream-level deviation of quantizer ( used to make
	overall bitrate of stream close to requested value ) */
static const float min_rc_quant_delta=.6f;
static const float max_rc_quant_delta=1.5f;

/*  Crispness parameter	controls threshold for decision whether
    to skip the frame or to code it. */
//static const float max_crispness=100.f;
/*	Maximum allowed number of skipped frames in a line. */
//static const int max_drops_line=0;					// CHL   We don't drop frames at the moment!


typedef struct entry_s
	/* max 28 bytes/frame or 5 Mb for 2-hour movie */
	{
		int quant;
		int text_bits;
		int motion_bits;
		int total_bits;
		float mult;
		short is_key_frame;
		short drop;
	} entry;

static int m_iCount;
static int m_iQuant;
/*static int m_iCrispness;*/
static short m_bDrop;
static float m_fQuant;

static int64_t m_lEncodedBits;
static int64_t m_lExpectedBits;

static FILE  *m_pFile;

static entry    vFrame;
static entry *m_vFrames;
static long	lFrameStart;

static int	iNumFrames;
static int	dummy;


void VbrControl_init_1pass_vbr(int quality, int crispness)
{
  m_fQuant=min_quantizer+((max_quantizer-min_quantizer)/6.)*(6-quality);
  m_iCount=0;
  m_bDrop=FALSE;
  VbrControl_update_1pass_vbr();
}

int VbrControl_init_2pass_vbr_analysis(const char *filename, int quality)
{
	m_pFile=fopen(filename, "wb");
	if(m_pFile==0)
		return -1;
	m_iCount=0;
	m_bDrop=FALSE;
	fprintf(m_pFile, "##version 1\n");
	fprintf(m_pFile, "quality %d\n", quality);
	return 0;
}

int VbrControl_init_2pass_vbr_encoding(const char *filename, int bitrate, double framerate, int crispness, int quality)
{
	int i;
	
	int64_t text_bits=0;
	int64_t total_bits=0;
	int64_t complexity=0;
	int64_t new_complexity=0;
	int64_t motion_bits=0;
	int64_t denominator=0;
	float qual_multiplier=1.;
	char head[20];

	int64_t desired_bits;
	int64_t non_text_bits;

	float average_complexity;

	m_pFile=fopen(filename, "rb");
	if(m_pFile==0)
		return -1;
	m_bDrop=FALSE;
	m_iCount=0;

	fread(head, 10, 1, m_pFile);
	if(!strncmp("##version ", head, 10))
	{
	    int version;
	    int iOldQual;
	    float old_qual, new_qual;
	    fscanf(m_pFile, "%d\n", &version);
	    fscanf(m_pFile, "quality %d\n", &iOldQual);
	    switch(iOldQual)
	    {
	    case 5:
		old_qual=1.f;
		break;
	    case 4:
		old_qual=1.1f;
		break;
	    case 3:
		old_qual=1.25f;
		break;
	    case 2:
		old_qual=1.4f;
		break;
	    case 1:
		old_qual=2.f;
		break;
	    }
	    switch(quality)
	    {
	    case 5:
		new_qual=1.f;
		break;
	    case 4:
		new_qual=1.1f;
		break;
	    case 3:
		new_qual=1.25f;
		break;
	    case 2:
		new_qual=1.4f;
		break;
	    case 1:
		new_qual=2.f;
		break;
	    }
	    qual_multiplier=new_qual/old_qual;	
	}
	else
	    fseek(m_pFile, 0, SEEK_SET);

	lFrameStart=ftell(m_pFile);		// save current position	

/* removed C++ dependencies, now read file twice :-( */

	
		while(!feof(m_pFile)) 
      {  fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n",
         &iNumFrames, &(vFrame.is_key_frame), &(vFrame.quant), &(vFrame.text_bits), &(vFrame.motion_bits), &(vFrame.total_bits));

                vFrame.total_bits+=vFrame.text_bits*(qual_multiplier-1);
                vFrame.text_bits*=qual_multiplier;
                text_bits +=(int64_t)vFrame.text_bits;
					 motion_bits += (int64_t)vFrame.motion_bits;
                total_bits +=(int64_t)vFrame.total_bits;
                complexity +=(int64_t)vFrame.text_bits*vFrame.quant;

//	printf("Frames %d, texture %d, motion %d, quant %d total %d ",
//		iNumFrames, vFrame.text_bits, vFrame.motion_bits, vFrame.quant, vFrame.total_bits);
//	printf("texture %d, total %d, complexity %lld \n",vFrame.text_bits,vFrame.total_bits, complexity);
	 	}
		iNumFrames++;
		average_complexity=complexity/iNumFrames;
		
//		if (verbose & TC_DEBUG)	{
//		    fprintf(stderr, "(%s) frames %d, texture %lld, motion %lld, total %lld, complexity %lld\n", __FILE__, iNumFrames, text_bits, motion_bits, total_bits, complexity);
//		}
		
		m_vFrames = (entry*)malloc(iNumFrames*sizeof(entry));
		if (!m_vFrames) 
		{	mp_msg(MSGT_FIXME, MSGL_FIXME,MSGTR_OutOfMemory);
			return -2; //TC_EXPORT_ERROR;
		}
			
	   fseek(m_pFile, lFrameStart, SEEK_SET);		// start again
		
		for (i=0;i1.5)
			    mult=1.5;
		}

		m_vFrames[i].mult=mult;
		m_vFrames[i].drop=FALSE;
		new_complexity+=m_vFrames[i].text_bits*m_vFrames[i].quant;

		denominator+=desired_bits*m_vFrames[i].mult/iNumFrames;
	}
	
	m_fQuant=((double)new_complexity)/(double)denominator;

	if(m_fQuantmax_quantizer) m_fQuant=max_quantizer;
	m_pFile=fopen("analyse.log", "wb");
	if(m_pFile)
	{
		fprintf(m_pFile, "Total frames: %d Avg quantizer: %f\n",
			iNumFrames, m_fQuant);
		fprintf(m_pFile, "Expecting %12lld bits\n", desired_bits+non_text_bits);
		fflush(m_pFile);
	}
	VbrControl_set_quant(m_fQuant*m_vFrames[0].mult);
	m_lEncodedBits=m_lExpectedBits=0;
	return 0;
}

int VbrControl_get_intra(void) 
{
	return m_vFrames[m_iCount].is_key_frame;
}

short VbrControl_get_drop(void) 
{
	return m_bDrop;
}

int VbrControl_get_quant(void) 
{
	return m_iQuant;
}

void VbrControl_set_quant(float quant)
{
	m_iQuant=quant;
	if((rand() % 10)<((quant-m_iQuant) * 10))
		m_iQuant++;
	if(m_iQuantmax_quantizer) m_iQuant=max_quantizer;
}

void VbrControl_update_1pass_vbr(void)
{
	VbrControl_set_quant(m_fQuant);
	m_iCount++;
}

void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits, int texture_bits, int total_bits, int quant)
{
	if(!m_pFile)
		return;
	fprintf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n",
		m_iCount, is_key_frame, quant, texture_bits, motion_bits, total_bits);
	m_iCount++;
}

void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits, int total_bits)
{
	double q;
	double dq;
		
	if(m_iCount>=iNumFrames)
		return;

	m_lExpectedBits+=(m_vFrames[m_iCount].total_bits-m_vFrames[m_iCount].text_bits)
		+ m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant/m_fQuant;
	m_lEncodedBits+=(int64_t)total_bits;

	if(m_pFile)
		fprintf(m_pFile, "Frame %d: PRESENT, complexity %d, quant multiplier %f, texture %d, total %d ",
				m_iCount, m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant,
					m_vFrames[m_iCount].mult, texture_bits, total_bits);

	m_iCount++;

	q = m_fQuant * m_vFrames[m_iCount].mult;
	if(qm_fQuant+max_quant_delta) q=m_fQuant+max_quant_delta;

	dq = (double)m_lEncodedBits/(double)m_lExpectedBits;
	dq*=dq;
	if(dqmax_rc_quant_delta) 
		dq=max_rc_quant_delta;
	if(m_iCount<20)					// no framerate corrections in first frames 
		dq=1;
	if(m_pFile)
		fprintf(m_pFile, "Progress: expected %12lld, achieved %12lld, dq %f",
			m_lExpectedBits, m_lEncodedBits, dq);
	q *= dq;
	VbrControl_set_quant(q);
	if(m_pFile)
		fprintf(m_pFile, ", new quant %d\n", m_iQuant);
}

void VbrControl_close(void)
{
	if(m_pFile)
	{
		fclose(m_pFile);
		m_pFile=NULL;
	}
	free(m_vFrames);
}