Mercurial > mplayer.hg
view divx4_vbr.c @ 13568:1cb0e1833515
Currently vbeGetProtModeInfo call the 0x4f0a function of int 10h the get
a simple 32 bits protected mode interface to some VESA functions. This
protected mode interface is interesting because it's quicker than the
raw int 10h interface.
Unfortunatly, begining with VBE 3.0, the 0x4f0a function is optional,
and some video cards don't implement it (3dfx, intel 845/855/865...).
This protected mode interface is then only used in vbeSetWindow and
vbeSetDisplayStart :
?- vbeSetWindow already implement an alternative methode if protected
mode interface is not available.
?- vbeSetDisplayStart also contain an alternative implementation, but
this one is disabled with a #if 0. I don't exactly know why because
it works well !
So currently, cards which don't have the 0x4f0a function are not
supported. This patch correct this.
?- vbeGetProtModeInfo failure is not fatal.
?- vbeSetDisplayStart has it's alternative implementation reenabled.
? ?it's used only with cards which don't have the 0x4f0a function
? ?so this won't make any difference for cards which were already
? ?working.
This patch also make the failure of vbeGetModeInfo not fatal. The
VBE 3.0 standard state that GetModeInfo can fail with some mode
which are listed as supported if the mode can't be used in the
current situation (not enough video memory for example). So a
failure of vbeGetModeInfo don't mean that other modes won't work
and should really not be fatal.
patch by Aurelien Jacobs <aurel@gnuage.org>
author | faust3 |
---|---|
date | Wed, 06 Oct 2004 08:42:13 +0000 |
parents | 772d6d27fd66 |
children | 11b249ef87b0 |
line wrap: on
line source
/* * 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 <gruel@gmx.de> * * Large parts of this code were taken from VbrControl() from the OpenDivX * project, (C) divxnetworks, written by Eugene Kuznetsov <ekuznetsov@divxnetworks.com> * with the permission of Darrius "Junto" Thompson, Director DivX */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <math.h> #include <inttypes.h> #include "divx4_vbr.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) { printf("out of memory"); return -2; //TC_EXPORT_ERROR; } fseek(m_pFile, lFrameStart, SEEK_SET); // start again for (i=0;i<iNumFrames;i++) { fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n", &dummy, &(m_vFrames[i].is_key_frame), &(m_vFrames[i].quant), &(m_vFrames[i].text_bits), &(m_vFrames[i].motion_bits), &(m_vFrames[i].total_bits)); m_vFrames[i].total_bits += m_vFrames[i].text_bits*(qual_multiplier-1); m_vFrames[i].text_bits *= qual_multiplier; } if (m_pFile) { fclose(m_pFile); m_pFile=NULL; } desired_bits=(int64_t)bitrate*(int64_t)iNumFrames/framerate; non_text_bits=total_bits-text_bits; if(desired_bits<=non_text_bits) { /* char s[200];*/ printf("Specified bitrate is too low for this clip.\n" "Minimum possible bitrate for the clip is %.0f kbps. Overriding\n" "user-specified value.\n", (float)(non_text_bits*framerate/(int64_t)iNumFrames)); desired_bits=non_text_bits*3/2; /* m_fQuant=max_quantizer; for(int i=0; i<iNumFrames; i++) { m_vFrames[i].drop=0; m_vFrames[i].mult=1; } VbrControl_set_quant(m_fQuant); return 0; */ } desired_bits -= non_text_bits; /** BRIEF EXPLANATION OF WHAT'S GOING ON HERE. We assume that text_bits=complexity / quantizer total_bits-text_bits = const(complexity) where 'complexity' is a characteristic of the frame and does not depend much on quantizer dynamics. Using this equation, we calculate 'average' quantizer to be used for encoding ( 1st order effect ). Having constant quantizer for the entire stream is not very convenient - reconstruction errors are more noticeable in low-motion scenes. To compensate this effect, we multiply quantizer for each frame by (complexity/average_complexity)^k, ( k - parameter of adjustment ). k=0 means 'no compensation' and k=1 is 'constant bitrate mode'. We choose something in between, like 0.5 ( 2nd order effect ). **/ average_complexity=complexity/iNumFrames; for(i=0; i<iNumFrames; i++) { float mult; if(m_vFrames[i].is_key_frame) { if((i+1<iNumFrames) && (m_vFrames[i+1].is_key_frame)) mult=1.25; else mult=.75; } else { mult=m_vFrames[i].text_bits*m_vFrames[i].quant; mult=(float)sqrt(mult/average_complexity); // if(i && m_vFrames[i-1].is_key_frame) // mult *= 0.75; if(mult<0.5) mult=0.5; if(mult>1.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_fQuant<min_quantizer) m_fQuant=min_quantizer; if(m_fQuant>max_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() { return m_vFrames[m_iCount].is_key_frame; } short VbrControl_get_drop() { return m_bDrop; } int VbrControl_get_quant() { return m_iQuant; } void VbrControl_set_quant(float quant) { m_iQuant=quant; if((rand() % 10)<((quant-m_iQuant) * 10)) m_iQuant++; if(m_iQuant<min_quantizer) m_iQuant=min_quantizer; if(m_iQuant>max_quantizer) m_iQuant=max_quantizer; } void VbrControl_update_1pass_vbr() { 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(q<m_fQuant+min_quant_delta) q=m_fQuant+min_quant_delta; if(q>m_fQuant+max_quant_delta) q=m_fQuant+max_quant_delta; dq = (double)m_lEncodedBits/(double)m_lExpectedBits; dq*=dq; if(dq<min_rc_quant_delta) dq=min_rc_quant_delta; if(dq>max_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() { if(m_pFile) { fclose(m_pFile); m_pFile=NULL; } free(m_vFrames); }