dbf-halloween2015

diff libs/vorbis/bitrate.c @ 1:c3f5c32cb210

barfed all the libraries in the source tree to make porting easier
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Nov 2015 00:36:56 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/vorbis/bitrate.c	Sun Nov 01 00:36:56 2015 +0200
     1.3 @@ -0,0 +1,253 @@
     1.4 +/********************************************************************
     1.5 + *                                                                  *
     1.6 + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
     1.7 + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
     1.8 + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
     1.9 + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
    1.10 + *                                                                  *
    1.11 + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
    1.12 + * by the Xiph.Org Foundation http://www.xiph.org/                  *
    1.13 + *                                                                  *
    1.14 + ********************************************************************
    1.15 +
    1.16 + function: bitrate tracking and management
    1.17 + last mod: $Id: bitrate.c 16227 2009-07-08 06:58:46Z xiphmont $
    1.18 +
    1.19 + ********************************************************************/
    1.20 +
    1.21 +#include <stdlib.h>
    1.22 +#include <string.h>
    1.23 +#include <math.h>
    1.24 +#include <ogg/ogg.h>
    1.25 +#include "vorbis/codec.h"
    1.26 +#include "codec_internal.h"
    1.27 +#include "os.h"
    1.28 +#include "misc.h"
    1.29 +#include "bitrate.h"
    1.30 +
    1.31 +/* compute bitrate tracking setup  */
    1.32 +void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
    1.33 +  codec_setup_info *ci=vi->codec_setup;
    1.34 +  bitrate_manager_info *bi=&ci->bi;
    1.35 +
    1.36 +  memset(bm,0,sizeof(*bm));
    1.37 +
    1.38 +  if(bi && (bi->reservoir_bits>0)){
    1.39 +    long ratesamples=vi->rate;
    1.40 +    int  halfsamples=ci->blocksizes[0]>>1;
    1.41 +
    1.42 +    bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
    1.43 +    bm->managed=1;
    1.44 +
    1.45 +    bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
    1.46 +    bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
    1.47 +    bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
    1.48 +
    1.49 +    bm->avgfloat=PACKETBLOBS/2;
    1.50 +
    1.51 +    /* not a necessary fix, but one that leads to a more balanced
    1.52 +       typical initialization */
    1.53 +    {
    1.54 +      long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
    1.55 +      bm->minmax_reservoir=desired_fill;
    1.56 +      bm->avg_reservoir=desired_fill;
    1.57 +    }
    1.58 +
    1.59 +  }
    1.60 +}
    1.61 +
    1.62 +void vorbis_bitrate_clear(bitrate_manager_state *bm){
    1.63 +  memset(bm,0,sizeof(*bm));
    1.64 +  return;
    1.65 +}
    1.66 +
    1.67 +int vorbis_bitrate_managed(vorbis_block *vb){
    1.68 +  vorbis_dsp_state      *vd=vb->vd;
    1.69 +  private_state         *b=vd->backend_state;
    1.70 +  bitrate_manager_state *bm=&b->bms;
    1.71 +
    1.72 +  if(bm && bm->managed)return(1);
    1.73 +  return(0);
    1.74 +}
    1.75 +
    1.76 +/* finish taking in the block we just processed */
    1.77 +int vorbis_bitrate_addblock(vorbis_block *vb){
    1.78 +  vorbis_block_internal *vbi=vb->internal;
    1.79 +  vorbis_dsp_state      *vd=vb->vd;
    1.80 +  private_state         *b=vd->backend_state;
    1.81 +  bitrate_manager_state *bm=&b->bms;
    1.82 +  vorbis_info           *vi=vd->vi;
    1.83 +  codec_setup_info      *ci=vi->codec_setup;
    1.84 +  bitrate_manager_info  *bi=&ci->bi;
    1.85 +
    1.86 +  int  choice=rint(bm->avgfloat);
    1.87 +  long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    1.88 +  long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
    1.89 +  long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
    1.90 +  int  samples=ci->blocksizes[vb->W]>>1;
    1.91 +  long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
    1.92 +  if(!bm->managed){
    1.93 +    /* not a bitrate managed stream, but for API simplicity, we'll
    1.94 +       buffer the packet to keep the code path clean */
    1.95 +
    1.96 +    if(bm->vb)return(-1); /* one has been submitted without
    1.97 +                             being claimed */
    1.98 +    bm->vb=vb;
    1.99 +    return(0);
   1.100 +  }
   1.101 +
   1.102 +  bm->vb=vb;
   1.103 +
   1.104 +  /* look ahead for avg floater */
   1.105 +  if(bm->avg_bitsper>0){
   1.106 +    double slew=0.;
   1.107 +    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
   1.108 +    double slewlimit= 15./bi->slew_damp;
   1.109 +
   1.110 +    /* choosing a new floater:
   1.111 +       if we're over target, we slew down
   1.112 +       if we're under target, we slew up
   1.113 +
   1.114 +       choose slew as follows: look through packetblobs of this frame
   1.115 +       and set slew as the first in the appropriate direction that
   1.116 +       gives us the slew we want.  This may mean no slew if delta is
   1.117 +       already favorable.
   1.118 +
   1.119 +       Then limit slew to slew max */
   1.120 +
   1.121 +    if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
   1.122 +      while(choice>0 && this_bits>avg_target_bits &&
   1.123 +            bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
   1.124 +        choice--;
   1.125 +        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.126 +      }
   1.127 +    }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
   1.128 +      while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
   1.129 +            bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
   1.130 +        choice++;
   1.131 +        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.132 +      }
   1.133 +    }
   1.134 +
   1.135 +    slew=rint(choice-bm->avgfloat)/samples*vi->rate;
   1.136 +    if(slew<-slewlimit)slew=-slewlimit;
   1.137 +    if(slew>slewlimit)slew=slewlimit;
   1.138 +    choice=rint(bm->avgfloat+= slew/vi->rate*samples);
   1.139 +    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.140 +  }
   1.141 +
   1.142 +
   1.143 +
   1.144 +  /* enforce min(if used) on the current floater (if used) */
   1.145 +  if(bm->min_bitsper>0){
   1.146 +    /* do we need to force the bitrate up? */
   1.147 +    if(this_bits<min_target_bits){
   1.148 +      while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
   1.149 +        choice++;
   1.150 +        if(choice>=PACKETBLOBS)break;
   1.151 +        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.152 +      }
   1.153 +    }
   1.154 +  }
   1.155 +
   1.156 +  /* enforce max (if used) on the current floater (if used) */
   1.157 +  if(bm->max_bitsper>0){
   1.158 +    /* do we need to force the bitrate down? */
   1.159 +    if(this_bits>max_target_bits){
   1.160 +      while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
   1.161 +        choice--;
   1.162 +        if(choice<0)break;
   1.163 +        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.164 +      }
   1.165 +    }
   1.166 +  }
   1.167 +
   1.168 +  /* Choice of packetblobs now made based on floater, and min/max
   1.169 +     requirements. Now boundary check extreme choices */
   1.170 +
   1.171 +  if(choice<0){
   1.172 +    /* choosing a smaller packetblob is insufficient to trim bitrate.
   1.173 +       frame will need to be truncated */
   1.174 +    long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
   1.175 +    bm->choice=choice=0;
   1.176 +
   1.177 +    if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
   1.178 +
   1.179 +      oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
   1.180 +      this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.181 +    }
   1.182 +  }else{
   1.183 +    long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
   1.184 +    if(choice>=PACKETBLOBS)
   1.185 +      choice=PACKETBLOBS-1;
   1.186 +
   1.187 +    bm->choice=choice;
   1.188 +
   1.189 +    /* prop up bitrate according to demand. pad this frame out with zeroes */
   1.190 +    minsize-=oggpack_bytes(vbi->packetblob[choice]);
   1.191 +    while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
   1.192 +    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
   1.193 +
   1.194 +  }
   1.195 +
   1.196 +  /* now we have the final packet and the final packet size.  Update statistics */
   1.197 +  /* min and max reservoir */
   1.198 +  if(bm->min_bitsper>0 || bm->max_bitsper>0){
   1.199 +
   1.200 +    if(max_target_bits>0 && this_bits>max_target_bits){
   1.201 +      bm->minmax_reservoir+=(this_bits-max_target_bits);
   1.202 +    }else if(min_target_bits>0 && this_bits<min_target_bits){
   1.203 +      bm->minmax_reservoir+=(this_bits-min_target_bits);
   1.204 +    }else{
   1.205 +      /* inbetween; we want to take reservoir toward but not past desired_fill */
   1.206 +      if(bm->minmax_reservoir>desired_fill){
   1.207 +        if(max_target_bits>0){ /* logical bulletproofing against initialization state */
   1.208 +          bm->minmax_reservoir+=(this_bits-max_target_bits);
   1.209 +          if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
   1.210 +        }else{
   1.211 +          bm->minmax_reservoir=desired_fill;
   1.212 +        }
   1.213 +      }else{
   1.214 +        if(min_target_bits>0){ /* logical bulletproofing against initialization state */
   1.215 +          bm->minmax_reservoir+=(this_bits-min_target_bits);
   1.216 +          if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
   1.217 +        }else{
   1.218 +          bm->minmax_reservoir=desired_fill;
   1.219 +        }
   1.220 +      }
   1.221 +    }
   1.222 +  }
   1.223 +
   1.224 +  /* avg reservoir */
   1.225 +  if(bm->avg_bitsper>0){
   1.226 +    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
   1.227 +    bm->avg_reservoir+=this_bits-avg_target_bits;
   1.228 +  }
   1.229 +
   1.230 +  return(0);
   1.231 +}
   1.232 +
   1.233 +int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
   1.234 +  private_state         *b=vd->backend_state;
   1.235 +  bitrate_manager_state *bm=&b->bms;
   1.236 +  vorbis_block          *vb=bm->vb;
   1.237 +  int                    choice=PACKETBLOBS/2;
   1.238 +  if(!vb)return 0;
   1.239 +
   1.240 +  if(op){
   1.241 +    vorbis_block_internal *vbi=vb->internal;
   1.242 +
   1.243 +    if(vorbis_bitrate_managed(vb))
   1.244 +      choice=bm->choice;
   1.245 +
   1.246 +    op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
   1.247 +    op->bytes=oggpack_bytes(vbi->packetblob[choice]);
   1.248 +    op->b_o_s=0;
   1.249 +    op->e_o_s=vb->eofflag;
   1.250 +    op->granulepos=vb->granulepos;
   1.251 +    op->packetno=vb->sequence; /* for sake of completeness */
   1.252 +  }
   1.253 +
   1.254 +  bm->vb=0;
   1.255 +  return(1);
   1.256 +}