⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 taudiofiltervolume.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
字号:
/*
 * Copyright (c) 2003-2006 Milan Cutka
 *
 * Volume normalizing code from mplayer by pl <p_l@gmx.fr>,
 *  sources: some ideas from volnorm plugin for xmms
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "stdafx.h"
#include "TaudioFilterVolume.h"
#include "IffdshowBase.h"
#include "IffdshowDecAudio.h"

const unsigned int TaudioFilterVolume::NSAMPLES=128;

// If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we
// choose to ignore the computed value as it's not significant enough
// FIXME: should depend on the frequency of the data (0.5s maybe)
const unsigned int TaudioFilterVolume::MIN_SAMPLE_SIZE=32000;

const float TaudioFilterVolume::MUL_INIT=1.0f;
const float TaudioFilterVolume::MUL_MIN=0.1f;
//const float TaudioFilterVolume::MUL_MAX=5.0f;

//const int TaudioFilterVolume::MIN_S16=-32768;
//const int TaudioFilterVolume::MAX_S16= 32767;

const float TaudioFilterVolume::MID_S16=/*MAX_S16**/0.25f;
const float TaudioFilterVolume::SIL_S16=/*MAX_S16**/0.001f;

template<class sample_t> void TaudioFilterVolume::volume(sample_t* const samples,size_t numsamples,const TsampleFormat &fmt,const TvolumeSettings *cfg)
{
 if (cfg->is)
  if (!cfg->normalize)
   {
    if (isVol)
     {
      typedef void (*TprocessVol)(sample_t * const samples,size_t numsamples,const int *volumes);
      static const TprocessVol processVol[7]=
       {
        NULL,
        &Tmultiply<1>::processVol,
        &Tmultiply<2>::processVol,
        &Tmultiply<3>::processVol,
        &Tmultiply<4>::processVol,
        &Tmultiply<5>::processVol,
        &Tmultiply<6>::processVol
       };
      processVol[fmt.nchannels](samples,numsamples,volumes);
     }
   }
  else
   {
    if (!mem)
     {
      mem=new Tmem[nSamples=oldcfg.nSamples];
      for (int i=0;i<nSamples;i++)
       {
        mem[i].len=0;
        mem[i].avg=0;
       }
     }

    size_t len=numsamples*fmt.nchannels;

    // Evaluate current samples average level
    float curavg=0.0f;
    for (size_t i=0;i<len;i++)
     {
      float tmp=float(samples[i]);
      curavg+=tmp*tmp;
     }
    curavg=sqrtf(curavg/float(len));

    // Evaluate an adequate 'mul' coefficient based on previous state, current samples level, etc
    float avg=0.0f;
    size_t totallen=0;
    for (int i=0;i<nSamples;i++)
     {
      avg+=mem[i].avg*(float)mem[i].len;
      totallen+=mem[i].len;
     }

    if (totallen>MIN_SAMPLE_SIZE)
     {
      avg/=(float)totallen;
      if (avg>=TsampleFormatInfo<sample_t>::max()*SIL_S16)
       mul=limit((float)(TsampleFormatInfo<sample_t>::max()*MID_S16)/avg,MUL_MIN,cfg->normalizeMax/100.0f);
     }

    // Scale & clamp the samples
    typedef void (*TprocessMul)(sample_t * const samples,size_t numsamples,const int *volumes,float mul);
    static const TprocessMul processMul[7]=
     {
      NULL,
      &Tmultiply<1>::processMul,
      &Tmultiply<2>::processMul,
      &Tmultiply<3>::processMul,
      &Tmultiply<4>::processMul,
      &Tmultiply<5>::processMul,
      &Tmultiply<6>::processMul
     };
    processMul[fmt.nchannels](samples,numsamples,volumes,mul);

    // Evaluation of newavg (not 100% accurate because of values clamping)
    float newavg=mul*curavg;
    // Stores computed values for future smoothing
    mem[idx].len=len;
    mem[idx].avg=newavg;
    idx=(idx+1)%nSamples;
   }
 if (numsamples>0 && deci->getParam2(IDFF_showCurrentVolume) && deci->getCfgDlgHwnd())
  {
   int64_t sum[6];memset(sum,0,sizeof(sum));
   for (size_t i=0;i<numsamples*fmt.nchannels;)
    for (unsigned int ch=0;ch<fmt.nchannels;ch++,i++)
     sum[ch]+=int64_t((int64_t)65536*ff_abs(samples[i]));
   CAutoLock lock(&csVolumes);
   for (unsigned int i=0;i<fmt.nchannels;i++)
    storedvolumes.volumes[i]=int((sum[i]/numsamples)/int64_t(TsampleFormatInfo<sample_t>::max()));
   storedvolumes.have=true;
  }
}

TaudioFilterVolume::TaudioFilterVolume(IffdshowBase *Ideci,Tfilters *Iparent):TaudioFilter(Ideci,Iparent)
{
 mem=NULL;
 mul=MUL_INIT;
 idx=0;
 oldfmt.freq=0;
 oldcfg.vol=-100;
 storedvolumes.have=false;
}
TaudioFilterVolume::~TaudioFilterVolume()
{
 if (mem) delete []mem;
}

bool TaudioFilterVolume::is(const TsampleFormat &fmt,const TfilterSettingsAudio *cfg)
{
 return !!cfg->is;
}

HRESULT TaudioFilterVolume::process(TfilterQueue::iterator it,TsampleFormat &fmt,void *samples,size_t numsamples,const TfilterSettingsAudio *cfg0)
{
 const TvolumeSettings *cfg=(const TvolumeSettings*)cfg0;
 if (oldfmt!=fmt || !cfg->equal(oldcfg))
  {
   //Kurosu: Yeah, struct packing made that a bug
   memcpy(&oldfmt, &fmt, sizeof(TsampleFormat));
   oldcfg=*cfg;
   if (mem) delete []mem;mem=NULL;
   isVol=false;
   static const int speakers[]={SPEAKER_FRONT_LEFT,SPEAKER_FRONT_RIGHT,SPEAKER_FRONT_CENTER,SPEAKER_BACK_LEFT|SPEAKER_BACK_CENTER,SPEAKER_BACK_RIGHT,SPEAKER_LOW_FREQUENCY};
   static const int TvolumeSettings::*cfgvols[]={&TvolumeSettings::volL,&TvolumeSettings::volR,&TvolumeSettings::volC,&TvolumeSettings::volSL,&TvolumeSettings::volSR,&TvolumeSettings::volLFE};
   static const int TvolumeSettings::*cfgmutes[]={&TvolumeSettings::volLmute,&TvolumeSettings::volRmute,&TvolumeSettings::volCmute,&TvolumeSettings::volSLmute,&TvolumeSettings::volSRmute,&TvolumeSettings::volLFEmute};
   unsigned int solo=0;
   for (unsigned int i=0;i<countof(speakers);i++)
    if (cfg->*cfgmutes[i]==2)
     {
      solo=speakers[i];
      break;
     }
   for (unsigned int i=0;i<fmt.nchannels;i++)
    {
     int v=100;
     for (int ii=0;i<countof(speakers);ii++)
      if (fmt.speakers[i]&speakers[ii])
       {
        v=cfg->*cfgmutes[ii]!=1 && (solo==0 || (fmt.speakers[i]&solo))?cfg->*cfgvols[ii]:0;
        break;
       }
     volumes[i]=v*cfg->vol/39;
     if (volumes[i]!=256) isVol=true;
    }
  }
 if (is(fmt,cfg))
  samples=init(cfg,fmt,samples,numsamples);
 if (numsamples>0)
  {
   switch (fmt.sf)
    {
     case TsampleFormat::SF_PCM16  :volume((int16_t*)samples,numsamples,fmt,cfg);break;
     case TsampleFormat::SF_PCM32  :volume((int32_t*)samples,numsamples,fmt,cfg);break;
     case TsampleFormat::SF_FLOAT32:volume((float*)  samples,numsamples,fmt,cfg);break;
    }
  }
 return (it!=NULL)?parent->deliverSamples(++it,fmt,samples,numsamples):S_OK;
}

void TaudioFilterVolume::onSeek(void)
{
 if (oldcfg.normalizeResetOnSeek)
 if (mem)
  {
   mul=MUL_INIT;
   delete []mem;mem=NULL;
  }
}

HRESULT TaudioFilterVolume::queryInterface(const IID &iid,void **ptr) const
{
 if (iid==IID_IaudioFilterVolume) {*ptr=(IaudioFilterVolume*)this;return S_OK;}
 else return E_NOINTERFACE;
}

STDMETHODIMP TaudioFilterVolume::getVolumeData(unsigned int *nchannels,int channels[],int vol[])
{
 if (!storedvolumes.have) return E_UNEXPECTED;
 if (!nchannels || !channels || !vol)  return E_POINTER;
 CAutoLock lock(&csVolumes);
 *nchannels=oldfmt.nchannels;
 memcpy(channels,oldfmt.speakers,oldfmt.nchannels*sizeof(int));
 memcpy(vol,storedvolumes.volumes,oldfmt.nchannels*sizeof(int));
 return S_OK;
}
STDMETHODIMP_(int) TaudioFilterVolume::getCurrentNormalization(void)
{
 return int(mul*100);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -