tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vorbis_bitrate.c (8478B)


      1 /********************************************************************
      2 *                                                                  *
      3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
      4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
      5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
      6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
      7 *                                                                  *
      8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
      9 * by the Xiph.Org Foundation https://xiph.org/                     *
     10 *                                                                  *
     11 ********************************************************************
     12 
     13 function: bitrate tracking and management
     14 
     15 ********************************************************************/
     16 
     17 #include <stdlib.h>
     18 #include <string.h>
     19 #include <math.h>
     20 #include <ogg/ogg.h>
     21 #include "vorbis/codec.h"
     22 #include "codec_internal.h"
     23 #include "os.h"
     24 #include "misc.h"
     25 #include "bitrate.h"
     26 
     27 /* compute bitrate tracking setup  */
     28 void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
     29  codec_setup_info *ci=vi->codec_setup;
     30  bitrate_manager_info *bi=&ci->bi;
     31 
     32  memset(bm,0,sizeof(*bm));
     33 
     34  if(bi && (bi->reservoir_bits>0)){
     35    long ratesamples=vi->rate;
     36    int  halfsamples=ci->blocksizes[0]>>1;
     37 
     38    bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
     39    bm->managed=1;
     40 
     41    bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
     42    bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
     43    bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
     44 
     45    bm->avgfloat=PACKETBLOBS/2;
     46 
     47    /* not a necessary fix, but one that leads to a more balanced
     48       typical initialization */
     49    {
     50      long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
     51      bm->minmax_reservoir=desired_fill;
     52      bm->avg_reservoir=desired_fill;
     53    }
     54 
     55  }
     56 }
     57 
     58 void vorbis_bitrate_clear(bitrate_manager_state *bm){
     59  memset(bm,0,sizeof(*bm));
     60  return;
     61 }
     62 
     63 int vorbis_bitrate_managed(vorbis_block *vb){
     64  vorbis_dsp_state      *vd=vb->vd;
     65  private_state         *b=vd->backend_state;
     66  bitrate_manager_state *bm=&b->bms;
     67 
     68  if(bm && bm->managed)return(1);
     69  return(0);
     70 }
     71 
     72 /* finish taking in the block we just processed */
     73 int vorbis_bitrate_addblock(vorbis_block *vb){
     74  vorbis_block_internal *vbi=vb->internal;
     75  vorbis_dsp_state      *vd=vb->vd;
     76  private_state         *b=vd->backend_state;
     77  bitrate_manager_state *bm=&b->bms;
     78  vorbis_info           *vi=vd->vi;
     79  codec_setup_info      *ci=vi->codec_setup;
     80  bitrate_manager_info  *bi=&ci->bi;
     81 
     82  int  choice=rint(bm->avgfloat);
     83  long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
     84  long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
     85  long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
     86  int  samples=ci->blocksizes[vb->W]>>1;
     87  long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
     88  if(!bm->managed){
     89    /* not a bitrate managed stream, but for API simplicity, we'll
     90       buffer the packet to keep the code path clean */
     91 
     92    if(bm->vb)return(-1); /* one has been submitted without
     93                             being claimed */
     94    bm->vb=vb;
     95    return(0);
     96  }
     97 
     98  bm->vb=vb;
     99 
    100  /* look ahead for avg floater */
    101  if(bm->avg_bitsper>0){
    102    double slew=0.;
    103    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
    104    double slewlimit= 15./bi->slew_damp;
    105 
    106    /* choosing a new floater:
    107       if we're over target, we slew down
    108       if we're under target, we slew up
    109 
    110       choose slew as follows: look through packetblobs of this frame
    111       and set slew as the first in the appropriate direction that
    112       gives us the slew we want.  This may mean no slew if delta is
    113       already favorable.
    114 
    115       Then limit slew to slew max */
    116 
    117    if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
    118      while(choice>0 && this_bits>avg_target_bits &&
    119            bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
    120        choice--;
    121        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    122      }
    123    }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
    124      while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
    125            bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
    126        choice++;
    127        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    128      }
    129    }
    130 
    131    slew=rint(choice-bm->avgfloat)/samples*vi->rate;
    132    if(slew<-slewlimit)slew=-slewlimit;
    133    if(slew>slewlimit)slew=slewlimit;
    134    choice=rint(bm->avgfloat+= slew/vi->rate*samples);
    135    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    136  }
    137 
    138 
    139 
    140  /* enforce min(if used) on the current floater (if used) */
    141  if(bm->min_bitsper>0){
    142    /* do we need to force the bitrate up? */
    143    if(this_bits<min_target_bits){
    144      while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
    145        choice++;
    146        if(choice>=PACKETBLOBS)break;
    147        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    148      }
    149    }
    150  }
    151 
    152  /* enforce max (if used) on the current floater (if used) */
    153  if(bm->max_bitsper>0){
    154    /* do we need to force the bitrate down? */
    155    if(this_bits>max_target_bits){
    156      while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
    157        choice--;
    158        if(choice<0)break;
    159        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    160      }
    161    }
    162  }
    163 
    164  /* Choice of packetblobs now made based on floater, and min/max
    165     requirements. Now boundary check extreme choices */
    166 
    167  if(choice<0){
    168    /* choosing a smaller packetblob is insufficient to trim bitrate.
    169       frame will need to be truncated */
    170    long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
    171    bm->choice=choice=0;
    172 
    173    if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
    174 
    175      oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
    176      this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    177    }
    178  }else{
    179    long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
    180    if(choice>=PACKETBLOBS)
    181      choice=PACKETBLOBS-1;
    182 
    183    bm->choice=choice;
    184 
    185    /* prop up bitrate according to demand. pad this frame out with zeroes */
    186    minsize-=oggpack_bytes(vbi->packetblob[choice]);
    187    while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
    188    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    189 
    190  }
    191 
    192  /* now we have the final packet and the final packet size.  Update statistics */
    193  /* min and max reservoir */
    194  if(bm->min_bitsper>0 || bm->max_bitsper>0){
    195 
    196    if(max_target_bits>0 && this_bits>max_target_bits){
    197      bm->minmax_reservoir+=(this_bits-max_target_bits);
    198    }else if(min_target_bits>0 && this_bits<min_target_bits){
    199      bm->minmax_reservoir+=(this_bits-min_target_bits);
    200    }else{
    201      /* inbetween; we want to take reservoir toward but not past desired_fill */
    202      if(bm->minmax_reservoir>desired_fill){
    203        if(max_target_bits>0){ /* logical bulletproofing against initialization state */
    204          bm->minmax_reservoir+=(this_bits-max_target_bits);
    205          if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
    206        }else{
    207          bm->minmax_reservoir=desired_fill;
    208        }
    209      }else{
    210        if(min_target_bits>0){ /* logical bulletproofing against initialization state */
    211          bm->minmax_reservoir+=(this_bits-min_target_bits);
    212          if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
    213        }else{
    214          bm->minmax_reservoir=desired_fill;
    215        }
    216      }
    217    }
    218  }
    219 
    220  /* avg reservoir */
    221  if(bm->avg_bitsper>0){
    222    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
    223    bm->avg_reservoir+=this_bits-avg_target_bits;
    224  }
    225 
    226  return(0);
    227 }
    228 
    229 int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
    230  private_state         *b=vd->backend_state;
    231  bitrate_manager_state *bm=&b->bms;
    232  vorbis_block          *vb=bm->vb;
    233  int                    choice=PACKETBLOBS/2;
    234  if(!vb)return 0;
    235 
    236  if(op){
    237    vorbis_block_internal *vbi=vb->internal;
    238 
    239    if(vorbis_bitrate_managed(vb))
    240      choice=bm->choice;
    241 
    242    op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
    243    op->bytes=oggpack_bytes(vbi->packetblob[choice]);
    244    op->b_o_s=0;
    245    op->e_o_s=vb->eofflag;
    246    op->granulepos=vb->granulepos;
    247    op->packetno=vb->sequence; /* for sake of completeness */
    248  }
    249 
    250  bm->vb=0;
    251  return(1);
    252 }