Blame lib/bitrate.c

Packit 06404a
/********************************************************************
Packit 06404a
 *                                                                  *
Packit 06404a
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Packit 06404a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 06404a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 06404a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 06404a
 *                                                                  *
Packit 06404a
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
Packit 06404a
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
Packit 06404a
 *                                                                  *
Packit 06404a
 ********************************************************************
Packit 06404a
Packit 06404a
 function: bitrate tracking and management
Packit 06404a
 last mod: $Id: bitrate.c 16227 2009-07-08 06:58:46Z xiphmont $
Packit 06404a
Packit 06404a
 ********************************************************************/
Packit 06404a
Packit 06404a
#include <stdlib.h>
Packit 06404a
#include <string.h>
Packit 06404a
#include <math.h>
Packit 06404a
#include <ogg/ogg.h>
Packit 06404a
#include "vorbis/codec.h"
Packit 06404a
#include "codec_internal.h"
Packit 06404a
#include "os.h"
Packit 06404a
#include "misc.h"
Packit 06404a
#include "bitrate.h"
Packit 06404a
Packit 06404a
/* compute bitrate tracking setup  */
Packit 06404a
void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  bitrate_manager_info *bi=&ci->bi;
Packit 06404a
Packit 06404a
  memset(bm,0,sizeof(*bm));
Packit 06404a
Packit 06404a
  if(bi && (bi->reservoir_bits>0)){
Packit 06404a
    long ratesamples=vi->rate;
Packit 06404a
    int  halfsamples=ci->blocksizes[0]>>1;
Packit 06404a
Packit 06404a
    bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
Packit 06404a
    bm->managed=1;
Packit 06404a
Packit 06404a
    bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
Packit 06404a
    bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
Packit 06404a
    bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
Packit 06404a
Packit 06404a
    bm->avgfloat=PACKETBLOBS/2;
Packit 06404a
Packit 06404a
    /* not a necessary fix, but one that leads to a more balanced
Packit 06404a
       typical initialization */
Packit 06404a
    {
Packit 06404a
      long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
Packit 06404a
      bm->minmax_reservoir=desired_fill;
Packit 06404a
      bm->avg_reservoir=desired_fill;
Packit 06404a
    }
Packit 06404a
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
void vorbis_bitrate_clear(bitrate_manager_state *bm){
Packit 06404a
  memset(bm,0,sizeof(*bm));
Packit 06404a
  return;
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_bitrate_managed(vorbis_block *vb){
Packit 06404a
  vorbis_dsp_state      *vd=vb->vd;
Packit 06404a
  private_state         *b=vd->backend_state;
Packit 06404a
  bitrate_manager_state *bm=&b->bms;
Packit 06404a
Packit 06404a
  if(bm && bm->managed)return(1);
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* finish taking in the block we just processed */
Packit 06404a
int vorbis_bitrate_addblock(vorbis_block *vb){
Packit 06404a
  vorbis_block_internal *vbi=vb->internal;
Packit 06404a
  vorbis_dsp_state      *vd=vb->vd;
Packit 06404a
  private_state         *b=vd->backend_state;
Packit 06404a
  bitrate_manager_state *bm=&b->bms;
Packit 06404a
  vorbis_info           *vi=vd->vi;
Packit 06404a
  codec_setup_info      *ci=vi->codec_setup;
Packit 06404a
  bitrate_manager_info  *bi=&ci->bi;
Packit 06404a
Packit 06404a
  int  choice=rint(bm->avgfloat);
Packit 06404a
  long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
  long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
Packit 06404a
  long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
Packit 06404a
  int  samples=ci->blocksizes[vb->W]>>1;
Packit 06404a
  long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
Packit 06404a
  if(!bm->managed){
Packit 06404a
    /* not a bitrate managed stream, but for API simplicity, we'll
Packit 06404a
       buffer the packet to keep the code path clean */
Packit 06404a
Packit 06404a
    if(bm->vb)return(-1); /* one has been submitted without
Packit 06404a
                             being claimed */
Packit 06404a
    bm->vb=vb;
Packit 06404a
    return(0);
Packit 06404a
  }
Packit 06404a
Packit 06404a
  bm->vb=vb;
Packit 06404a
Packit 06404a
  /* look ahead for avg floater */
Packit 06404a
  if(bm->avg_bitsper>0){
Packit 06404a
    double slew=0.;
Packit 06404a
    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
Packit 06404a
    double slewlimit= 15./bi->slew_damp;
Packit 06404a
Packit 06404a
    /* choosing a new floater:
Packit 06404a
       if we're over target, we slew down
Packit 06404a
       if we're under target, we slew up
Packit 06404a
Packit 06404a
       choose slew as follows: look through packetblobs of this frame
Packit 06404a
       and set slew as the first in the appropriate direction that
Packit 06404a
       gives us the slew we want.  This may mean no slew if delta is
Packit 06404a
       already favorable.
Packit 06404a
Packit 06404a
       Then limit slew to slew max */
Packit 06404a
Packit 06404a
    if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
Packit 06404a
      while(choice>0 && this_bits>avg_target_bits &&
Packit 06404a
            bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
Packit 06404a
        choice--;
Packit 06404a
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
      }
Packit 06404a
    }else if(bm->avg_reservoir+(this_bits-avg_target_bits)
Packit 06404a
      while(choice+1
Packit 06404a
            bm->avg_reservoir+(this_bits-avg_target_bits)
Packit 06404a
        choice++;
Packit 06404a
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
Packit 06404a
    slew=rint(choice-bm->avgfloat)/samples*vi->rate;
Packit 06404a
    if(slew<-slewlimit)slew=-slewlimit;
Packit 06404a
    if(slew>slewlimit)slew=slewlimit;
Packit 06404a
    choice=rint(bm->avgfloat+= slew/vi->rate*samples);
Packit 06404a
    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
  }
Packit 06404a
Packit 06404a
Packit 06404a
Packit 06404a
  /* enforce min(if used) on the current floater (if used) */
Packit 06404a
  if(bm->min_bitsper>0){
Packit 06404a
    /* do we need to force the bitrate up? */
Packit 06404a
    if(this_bits
Packit 06404a
      while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
Packit 06404a
        choice++;
Packit 06404a
        if(choice>=PACKETBLOBS)break;
Packit 06404a
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* enforce max (if used) on the current floater (if used) */
Packit 06404a
  if(bm->max_bitsper>0){
Packit 06404a
    /* do we need to force the bitrate down? */
Packit 06404a
    if(this_bits>max_target_bits){
Packit 06404a
      while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
Packit 06404a
        choice--;
Packit 06404a
        if(choice<0)break;
Packit 06404a
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* Choice of packetblobs now made based on floater, and min/max
Packit 06404a
     requirements. Now boundary check extreme choices */
Packit 06404a
Packit 06404a
  if(choice<0){
Packit 06404a
    /* choosing a smaller packetblob is insufficient to trim bitrate.
Packit 06404a
       frame will need to be truncated */
Packit 06404a
    long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
Packit 06404a
    bm->choice=choice=0;
Packit 06404a
Packit 06404a
    if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
Packit 06404a
Packit 06404a
      oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
Packit 06404a
      this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
    }
Packit 06404a
  }else{
Packit 06404a
    long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
Packit 06404a
    if(choice>=PACKETBLOBS)
Packit 06404a
      choice=PACKETBLOBS-1;
Packit 06404a
Packit 06404a
    bm->choice=choice;
Packit 06404a
Packit 06404a
    /* prop up bitrate according to demand. pad this frame out with zeroes */
Packit 06404a
    minsize-=oggpack_bytes(vbi->packetblob[choice]);
Packit 06404a
    while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
Packit 06404a
    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
Packit 06404a
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* now we have the final packet and the final packet size.  Update statistics */
Packit 06404a
  /* min and max reservoir */
Packit 06404a
  if(bm->min_bitsper>0 || bm->max_bitsper>0){
Packit 06404a
Packit 06404a
    if(max_target_bits>0 && this_bits>max_target_bits){
Packit 06404a
      bm->minmax_reservoir+=(this_bits-max_target_bits);
Packit 06404a
    }else if(min_target_bits>0 && this_bits
Packit 06404a
      bm->minmax_reservoir+=(this_bits-min_target_bits);
Packit 06404a
    }else{
Packit 06404a
      /* inbetween; we want to take reservoir toward but not past desired_fill */
Packit 06404a
      if(bm->minmax_reservoir>desired_fill){
Packit 06404a
        if(max_target_bits>0){ /* logical bulletproofing against initialization state */
Packit 06404a
          bm->minmax_reservoir+=(this_bits-max_target_bits);
Packit 06404a
          if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
Packit 06404a
        }else{
Packit 06404a
          bm->minmax_reservoir=desired_fill;
Packit 06404a
        }
Packit 06404a
      }else{
Packit 06404a
        if(min_target_bits>0){ /* logical bulletproofing against initialization state */
Packit 06404a
          bm->minmax_reservoir+=(this_bits-min_target_bits);
Packit 06404a
          if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
Packit 06404a
        }else{
Packit 06404a
          bm->minmax_reservoir=desired_fill;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* avg reservoir */
Packit 06404a
  if(bm->avg_bitsper>0){
Packit 06404a
    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
Packit 06404a
    bm->avg_reservoir+=this_bits-avg_target_bits;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
Packit 06404a
  private_state         *b=vd->backend_state;
Packit 06404a
  bitrate_manager_state *bm=&b->bms;
Packit 06404a
  vorbis_block          *vb=bm->vb;
Packit 06404a
  int                    choice=PACKETBLOBS/2;
Packit 06404a
  if(!vb)return 0;
Packit 06404a
Packit 06404a
  if(op){
Packit 06404a
    vorbis_block_internal *vbi=vb->internal;
Packit 06404a
Packit 06404a
    if(vorbis_bitrate_managed(vb))
Packit 06404a
      choice=bm->choice;
Packit 06404a
Packit 06404a
    op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
Packit 06404a
    op->bytes=oggpack_bytes(vbi->packetblob[choice]);
Packit 06404a
    op->b_o_s=0;
Packit 06404a
    op->e_o_s=vb->eofflag;
Packit 06404a
    op->granulepos=vb->granulepos;
Packit 06404a
    op->packetno=vb->sequence; /* for sake of completeness */
Packit 06404a
  }
Packit 06404a
Packit 06404a
  bm->vb=0;
Packit 06404a
  return(1);
Packit 06404a
}