ffmpeg player sound effect and tone the same transfer speed 2-

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/xjb2006/article/details/86063307

Speed ​​of sound about the same tune, or just a simple tone, a lot of the video player or audio player or mobile terminal APP implement this functionality. Such as Tencent video, I love the Fantastic Art video, Youku video. . . . . . And we mainly SoundTouch open source to achieve: SoundTouch is a very good audio processing algorithms, the famous open-source Android-side development is SoundTouch ijkplayer algorithm used to achieve the same transfer speed.

But if both variable-speed audio and video the same tune, um, in fact, that complex and complicated and that simple and simple, if the player source code is their own doing, we can make the video to synchronize audio, audio faster, proven audio data reduction, the video frame will be discarded. If the audio slow, proof of audio data increases, it will be slower to switch video frames.

Directly attached to the source of it:

Here is my encapsulated header file:

#pragma once
#include "SoundTouch.h"
using namespace soundtouch;

class CSoundTouchEx
{
public:
	CSoundTouchEx(void);
	~CSoundTouchEx(void);

private:
	int m_nChannels;
	float m_fTempo;
	float m_fRate;
	SoundTouch m_soundtouch;




public:
	float GetTempo()
	{
		return m_fTempo;
	}
	bool SetTempo(float nTempo);
	float GetRate()
	{
		return m_fRate;
	}
	bool SetRate(float nRate);

	int TempoProcess(char *pOutBuf,char *pInBuf,int nInDataCount);
	void SetTempoFormat(int sampleRate=44100,int channels=2)
	{ 
		m_soundtouch.setSampleRate(sampleRate);
		m_soundtouch.setChannels(channels);
		m_nChannels=channels;

		m_soundtouch.setSetting(SETTING_USE_QUICKSEEK, 0);
		m_soundtouch.setSetting(SETTING_USE_AA_FILTER, 1);
	}

	bool shortTOfloat(const short *pShort,int nNum,float *pFloat)
	{
		double fscale = 1.0 / 32768.0;
		// convert to floats, scale to range [-1..+1[
		for (int i = 0; i < nNum; i ++)
		{
			pFloat[i] = (float)(fscale * (double)pShort[i]);
		}

		return true;
	}

	bool floatTOshort(const float *pFloat,int nNum,short *pShort)
	{
		int iTemp=0;

		// convert to 16 bit integer
		for (int i = 0; i < nNum; i ++)
		{
			// convert to integer
			iTemp = (int)(32768.0f * pFloat[i]);

			// saturate
			if (iTemp < -32768) iTemp = -32768;
			if (iTemp > 32767)  iTemp = 32767;
			pShort[i] = (short)iTemp;
		}
		
		return true;
	}
};

Next is the realization of the CPP Source:

#include "StdAfx.h"
#include ".\soundtouchex.h"

CSoundTouchEx::CSoundTouchEx(void)
{
	m_fRate=1;
	m_fTempo=0;
	m_nChannels=2;
}

CSoundTouchEx::~CSoundTouchEx(void)
{
}


bool CSoundTouchEx::SetRate(float nRate)
{
	//if(nRate<-50) 
	//	return false;
	//if(nRate>900)
	//	return false;
	//m_soundtouch.setRateChange(nRate);
	m_soundtouch.setPitch(nRate);
	m_fRate=nRate;
	return true;
}

bool CSoundTouchEx::SetTempo(float nTempo)
{
	if(nTempo<-50)
		return false;
	if(nTempo>900)
		return false;
	//m_soundtouch.setRateChange(nTempo);
	m_soundtouch.setTempoChange(nTempo);
	m_fTempo=nTempo;
	return true;
}

int CSoundTouchEx::TempoProcess(char *pOutBuf,char *pInBuf,int nInDataCount)
{
	int nChannels=m_nChannels;
	short *pOutBuf1=(short*)pOutBuf;
	int nOut=0;
	DWORD time1=::timeGetTime();

	//m_soundtouch.flush();

	const int tempoBUFSIZE=(1024*2);

	//SAMPLETYPE *pNewBuf=new SAMPLETYPE[nInDataCount];
	SAMPLETYPE pNewBuf[1024*64];
	//memset(pNewBuf,0,sizeof(SAMPLETYPE)*nInDataCount);
	shortTOfloat((short*)pInBuf,nInDataCount,pNewBuf);
	int nAllSize=0;
	int nPointer=0;
	SAMPLETYPE *pBuf=0;
	for(;;)
	{
		int nTrueLen=0;
		SAMPLETYPE *pBuf=pNewBuf+nPointer;
		nPointer+=tempoBUFSIZE;
		nTrueLen=tempoBUFSIZE;
		if(nPointer>=nInDataCount)
		{
			nTrueLen=nInDataCount-nPointer+tempoBUFSIZE;
			nPointer+=nTrueLen;
		}

		int buffSizeSamples=nTrueLen/nChannels;
		// Feed the samples into SoundTouch processor
		m_soundtouch.putSamples((SAMPLETYPE*)pBuf, buffSizeSamples);
		int nSamples=0;
		
		do 
		{
			nSamples = m_soundtouch.receiveSamples((SAMPLETYPE*)pBuf, buffSizeSamples);
			floatTOshort(pBuf,nSamples*nChannels,(short*)(pOutBuf1+nAllSize));
			nAllSize+=nSamples*nChannels;


		} while (nSamples != 0);

		if(nPointer>=nInDataCount)
			break;
	}


	//if(pNewBuf)
	//	delete []pNewBuf;
	DWORD time2=::timeGetTime()-time1;
	return nAllSize*2;//因为是char
}

Calling code segment:

int CXiaoPlayer::OutAudio(BYTE *pPCM,int nlen,int c,int s,int b,int pts)
{
    m_soundtouch.SetTempoFormat(s,c);
    //变速不变调
    BYTE *TempoBuf=new BYTE[1024*200]; 
    int nBytes=nlen;
    if(m_soundtouch.GetTempo()!=0||m_soundtouch.GetRate()!=1)
    {
        try
        {
            nBytes=m_soundtouch.TempoProcess((char*)TempoBuf,(char*)pPCM,nlen/2);
        }
        catch(...)
        {
            TRACE0("CAudioPlay:TempoProcess错误\n");
            m_soundtouch.SetTempo(0);
        }
    }
    else
    {
        memcpy(TempoBuf,pPCM,nlen);
        nBytes=nlen;
    }

    if(nBytes>0)
    {
        WAVEFORMATEX waveformat;
        memset(&waveformat, 0, sizeof(WAVEFORMATEX));
        waveformat.cbSize = sizeof(WAVEFORMATEX);
        waveformat.wFormatTag = WAVE_FORMAT_PCM; // pcm
        waveformat.nChannels = c; //
        waveformat.nSamplesPerSec = s; // 
        waveformat.wBitsPerSample = b; // 
        waveformat.nBlockAlign = waveformat.nChannels * waveformat.wBitsPerSample / 8;
        waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * waveformat.nBlockAlign;    
        PlayAudio(TempoBuf,nBytes,(BYTE*)&waveformat,pts);
        
    }
    delete []TempoBuf;
    return nBytes;
}
 

OK! Today, stop here!

If you have the need for cooperation: Contact QQ35744025,10 years of professional experience in the development of audio and video, welcome harassment.

Guess you like

Origin blog.csdn.net/xjb2006/article/details/86063307