sdl在一些电脑上无法播放出声音

公司任务是从流媒体发送内存aac数据通过解码,调用ffmpeg进行解码,使用sdl进行播放,本来顺理成章的播放很是没有问题,但在老大的电脑上怎么也播不出声音来,纠结好几天终于找到问题了,在sdl初始化之前需要进行com库初始化,使其支持子线程进行音频的播放。附源码:

#include "Stdafx.h"
#include "aac.h"
#include <process.h>
#include "objbase.h"


#define MAX_AUDIO_FRAME_SIZE 192000
#define CHANNEL 2
#define BITS_PER_SAMPLE 	16
#define SAMPLE_PER_SEC 44100

CRITICAL_SECTION g_csLock;
static int g_countLock = 0;

/* The audio function callback takes the following parameters: 
 * stream: A pointer to the audio buffer to be filled 
 * len: The length (in bytes) of the audio buffer 
*/ 
void  AACPlay::fill_audio(void *udata,Uint8 *stream,int len){ 
	AACPlay* pThis = (AACPlay*)udata;
	if(pThis->m_audio_len==0)		/*  Only  play  if  we  have  data  left  */ 
		return; 
	//SDL 2.0
	EnterCriticalSection(&g_csLock);
	SDL_memset(stream, 0, len);
	len=(len>pThis->m_audio_len?pThis->m_audio_len:len);	/*  Mix  as  much  data  as  possible  */ 
	SDL_MixAudio(stream,pThis->m_audio_pos,len,SDL_MIX_MAXVOLUME);
	LeaveCriticalSection(&g_csLock);
	pThis->m_audio_pos += len; 
	pThis->m_audio_len -= len; 
}

AACPlay::AACPlay(void)
{	
	///解码
	m_pDecodeFormatCtx	= NULL;
	m_pDecodeCodecCtx		= NULL;
	m_pDecodeCodec			= NULL;
	m_pDecodeFrame			= NULL;	
	m_pDecodeSwrCtx			= NULL;
	m_nAudioStreamIndex	=-1;
	m_nDecodeBuffSize		= 0;
	m_pDecodeFrameBuff	= NULL;
	m_memblockPool			= NULL;

	m_audio_len						= 0;
	m_audio_chunk				= NULL;
	m_audio_pos					= NULL;
	m_bOpenSDLorNot			= FALSE;
	
	m_nLastErrorCode					= ITAV_NoEro;
	m_pDecodeTempOutBuff		= NULL;
	m_decodeCodecID					= AV_CODEC_ID_NONE;
	m_pDecodeCodecParserCtx = NULL;
	m_ThrHandle							= NULL;
	
	if(!g_countLock)
	{
		InitializeCriticalSection(&g_csLock);
		g_countLock ++;
	}
}


AACPlay::~AACPlay(void)
{
	SDL_CloseAudio();//Close SDL
	SDL_Quit();
	if(m_memblockPool)
	{
		delete m_memblockPool;
		m_memblockPool = NULL;
	}
	deleteAllDecodeInfo();
	g_countLock --;
	if(g_countLock <= 0)
		DeleteCriticalSection(&g_csLock);
}

//************************************
//函数名:  initDecode
//描述:初始化解码函数
//参数:无
//返回值:int
//时间:2015/7/31 WZQ
//************************************
int AACPlay::initDecode()
{	
	resetLastErrorCode();	
	avcodec_register_all();
	m_pDecodeFormatCtx = avformat_alloc_context();	
	if(m_decodeCodecID == AV_CODEC_ID_NONE)
		m_decodeCodecID = AV_CODEC_ID_AAC;
	m_pDecodeCodec = avcodec_find_decoder(m_decodeCodecID);
	if (!m_pDecodeCodec)
	{
		m_nLastErrorCode = ITAV_FindDecoderEro;		
		return m_nLastErrorCode;
	}

	m_pDecodeCodecCtx =  avcodec_alloc_context3(m_pDecodeCodec);
	if (!m_pDecodeCodecCtx)
	{
		fprintf(stderr, "Could not allocate video codec context\n");
		m_nLastErrorCode = ITAV_DecodeAllocCtxFailed;
		return m_nLastErrorCode;
	}	
	m_pDecodeCodecParserCtx = av_parser_init(m_decodeCodecID);
	if (!m_pDecodeCodecParserCtx)
	{
		printf("Could not allocate video parser context\n");
		m_nLastErrorCode = ITAV_DecodeCodecParserCtxFailed;
		return m_nLastErrorCode;
	}
	if (avcodec_open2(m_pDecodeCodecCtx, m_pDecodeCodec,NULL) < 0)
	{
		m_nLastErrorCode = ITAV_OpenDecoderEro;		
		return m_nLastErrorCode;
	}

	av_init_packet(&m_decodePacket);
	m_pDecodeFrame = av_frame_alloc();
	if(!m_pDecodeFrame)
	{
		m_nLastErrorCode = ITAV_DecodeAllocFrameFailed;
		return m_nLastErrorCode;
	}	
	///设置输出音频格式	
	m_decodeSampleFmt=AV_SAMPLE_FMT_S16;	
	m_pDecodeFrameBuff = (uint8_t *)av_malloc(1000000);	
	m_pDecodeTempOutBuff = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);
        ///在这进行com的初始化为支持多线程
       CoInitializeEx(NULL, COINIT_MULTITHREADED);
	//Init
	if(SDL_Init(/*SDL_INIT_VIDEO | */SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
		printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
		m_nLastErrorCode = ITAV_SDLINITERROR;
		return m_nLastErrorCode;
	}
	
	//SDL_AudioSpec
	m_wanted_spec.freq = SAMPLE_PER_SEC; 
	m_wanted_spec.format = AUDIO_S16SYS; 
	m_wanted_spec.channels = CHANNEL; 
	m_wanted_spec.silence = 0; 
	m_wanted_spec.samples = m_pDecodeCodecCtx->frame_size; 
	m_wanted_spec.callback = &AACPlay::fill_audio; 
	m_wanted_spec.userdata = this;

	m_memblockPool = new INMSMemBlockPool(4096);
	if(!m_memblockPool)
	{
		m_nLastErrorCode = ITAV_MallocEro;
		return m_nLastErrorCode;
	}
	m_hEventInput			= CreateEvent(NULL,FALSE,FALSE,NULL);
	m_hEventPlay			= CreateEvent(NULL,FALSE,FALSE,NULL);
	m_hEventPlayStop	= CreateEvent(NULL,FALSE,FALSE,NULL);


	return m_nLastErrorCode;
}

//************************************     
// 函数名称: Play     
// 函数说明:开始播放,启动解码播放          
// 返 回 值: void     
//************************************  
void AACPlay::Play()
{
	unsigned tmpid;
	m_ThrHandle=reinterpret_cast<HANDLE>(_beginthreadex(0,0,DecodeAudioThread,this,0,&tmpid));
	if(m_ThrHandle)
	{
		SetEvent(m_hEventInput);
	}
}

//************************************     
// 函数名称: DecodeAudioThread     
// 函数说明:解码播放线程         
// 返 回 值: unsigned     
// 参    数: void * pParam     
//************************************  
unsigned AACPlay::DecodeAudioThread(void* pParam)
{
	AACPlay* pthis = (AACPlay*)pParam;
	pthis->decodeOutput();
	return 0;
}
//************************************     
// 函数名称: decodeInput     
// 函数说明:解码输入          
// 返 回 值: int     
// 参    数: unsigned char * strSrcBuf     
// 参    数: int nSrcLen     
//************************************  
int AACPlay::decodeInput(unsigned char* strSrcBuf,int nSrcLen)
{
	resetLastErrorCode();
	if(WAIT_OBJECT_0 == WaitForSingleObject(m_hEventInput,INFINITE))
	{
		if(m_memblockPool!=NULL && strSrcBuf != NULL && nSrcLen > 0)
		{
			INMSMemBlock* tempblock = new INMSMemBlock(nSrcLen);
			tempblock->addData(strSrcBuf,nSrcLen);
			m_memblockPool->pushMemBlock(tempblock);
			SetEvent(m_hEventPlay);
		}
	}
	return ITAV_NoEro;
}
//************************************
//函数名:  decodeInput(char* strSrcBuf,int nSrcLen,char** strDestBuf,int &nDestLen)
//描述:解码数据  输出
//参数:输入数据,输入大小,输出的指针,输出大小
//返回值:int <0 失败  
//注意:此函数不支持外部多线程编程,因为此部分未线程锁
//时间:2015/7/23 WZQ
//************************************
int AACPlay::decodeOutput()
{
	resetLastErrorCode();
	int cur_size,got_frame,ret;
	const int in_buffer_size=4096;	
	uint8_t *cur_ptr;
	while (1) 
	{		
		HANDLE hEvent[2] = {m_hEventPlay,m_hEventPlayStop};
		int ret = WaitForMultipleObjects(2,hEvent,FALSE,INFINITE);
		if(ret == WAIT_OBJECT_0)
		{
			INMSMemBlock* memBlock = m_memblockPool->popMemBlock();
			cur_size = memBlock->dataSize();
			cur_ptr=memBlock->data();//m_pDecodeFrameBuff;
			while (cur_size>0)
			{
				///解析一包数据
				int len = av_parser_parse2(m_pDecodeCodecParserCtx,m_pDecodeCodecCtx,&m_decodePacket.data,
					&m_decodePacket.size,cur_ptr,cur_size,AV_NOPTS_VALUE,AV_NOPTS_VALUE,AV_NOPTS_VALUE);
				cur_ptr += len;
				cur_size -= len;
				if(m_decodePacket.size==0)
					continue;
				//Some Info from AVCodecParserContext
				///打印当前解析的一些信息
				printf("[Packet]Size:%6d\t",m_decodePacket.size);			
										 //AV_SAMPLE_FMT_FLTP
				ret = avcodec_decode_audio4(m_pDecodeCodecCtx, m_pDecodeFrame,&got_frame, &m_decodePacket);
				if (ret < 0) 
				{
					m_nLastErrorCode = ITAV_DecodeEro;
					break;
				}
				if(got_frame)
				{				
					if(!m_pDecodeSwrCtx)
					{
						m_pDecodeSwrCtx = swr_alloc();
						int64_t channelslayout = av_get_default_channel_layout(m_pDecodeFrame->channels);
						AVSampleFormat out_fmt = AV_SAMPLE_FMT_S16;//目标格式  
						m_pDecodeSwrCtx=swr_alloc_set_opts(m_pDecodeSwrCtx,av_get_default_channel_layout(m_pDecodeFrame->channels), out_fmt, m_pDecodeFrame->sample_rate,
							av_get_default_channel_layout(m_pDecodeCodecCtx->channels),m_pDecodeCodecCtx->sample_fmt , m_pDecodeCodecCtx->sample_rate,0, NULL);
						swr_init(m_pDecodeSwrCtx);					
					}
					///如果需要重采样,把下面函数打开,把此三行屏蔽即可
					swr_convert(m_pDecodeSwrCtx,&m_pDecodeTempOutBuff,  swr_get_out_samples(m_pDecodeSwrCtx,m_pDecodeFrame->nb_samples) ,(const uint8_t **)m_pDecodeFrame->data,m_pDecodeFrame->nb_samples);
					int out_nb_samples=m_pDecodeFrame->nb_samples;	///还是用的老的采样率

					
					//printf("%d\n",m_pDecodeCodecCtx->codec->sample_fmts[0]);
					if(!m_bOpenSDLorNot)
					{
						m_wanted_spec.freq			= m_pDecodeFrame->sample_rate;
						//AUDIO_U16LSB; 
						m_wanted_spec.channels	= m_pDecodeFrame->channels; 
						switch(m_pDecodeCodecCtx->sample_fmt)
						{
						case	AV_SAMPLE_FMT_S16P: 
						case	AV_SAMPLE_FMT_FLTP:  
						case	AV_SAMPLE_FMT_S16:
						case	AV_SAMPLE_FMT_NONE:
						case	AV_SAMPLE_FMT_FLT:
							m_wanted_spec.format = AUDIO_S16;
							break;
						case AV_SAMPLE_FMT_U8:
							m_wanted_spec.format = AUDIO_U8;
							break;
						case AV_SAMPLE_FMT_S32:
							m_wanted_spec.format	= AUDIO_F32;
							break;///< signed 32 bits
						case AV_SAMPLE_FMT_DBL:
							m_wanted_spec.format	= AUDIO_F32;
							break;///< double
						case AV_SAMPLE_FMT_DBLP:
							m_wanted_spec.format	= AUDIO_F32;
							break;///< double, planar

						default:
							m_wanted_spec.format		= AUDIO_S16LSB;
							break;
						}
						m_wanted_spec.silence		= 0; 
						m_wanted_spec.samples	= /*m_pDecodeFrame->nb_samples*//*m_pDecodeCodecCtx->frame_size*/out_nb_samples;
						m_bOpenSDLorNot				= TRUE;
						if (SDL_OpenAudio(&m_wanted_spec, NULL)<0){ 
							SDL_ClearError();
							printf("Failed to open audio: %s\n", SDL_GetError());
							m_nLastErrorCode = ITAV_SDLOPENERROR;
							return m_nLastErrorCode; 
						} 
					}
					//获取的大小也应该为目标格式
					m_nDecodeBuffSize = av_samples_get_buffer_size(NULL,m_pDecodeCodecCtx->channels ,out_nb_samples,AV_SAMPLE_FMT_S16,1);
					///如果只使用默认转换 打开上面三行 屏蔽下面一行即可
					//	m_nDecodeBuffSize = AudioResampling(m_pDecodeCodecCtx,m_pDecodeFrame,m_decodeSampleFmt,m_decodeCodecFmt.nDstChannels,m_decodeCodecFmt.nDstSampleRate,m_pDecodeTempOutBuff);
					m_nDecodeFrameCount++;
					printf("Succeed to decode 1 frame!\n");
				}
				m_audio_chunk	= (Uint8 *) m_pDecodeTempOutBuff;
				m_audio_len			=  m_nDecodeBuffSize;
				m_audio_pos		= m_audio_chunk;
				SDL_PauseAudio(0);
				while(m_audio_len>0)//Wait until finish
					SDL_Delay(1); 
			}
			SetEvent(m_hEventInput);
		}
		else if(ret == WAIT_OBJECT_0+1)
			break;
	}	
	return m_nLastErrorCode;	
}

//************************************     
// 函数名称: Stop     
// 函数说明:停止音频播放线程          
// 返 回 值: void     
//************************************  
void AACPlay::Stop()
{
	SetEvent(m_hEventPlayStop);
	::WaitForSingleObject(m_ThrHandle,INFINITE);
	if	(m_ThrHandle!=0)
	{
		::CloseHandle(m_ThrHandle);
		m_ThrHandle = 0;
	}
	CloseHandle(m_hEventInput);
	CloseHandle(m_hEventPlay);
	CloseHandle(m_hEventPlayStop);
	deleteAllDecodeInfo();
}

//************************************     
// 函数名称: resetLastErrorCode     
// 函数说明:重置上一个错误          
// 返 回 值: void     
//************************************  
void AACPlay::resetLastErrorCode()
{
	m_nLastErrorCode = ITAV_NoEro;
}

//************************************     
// 函数名称: deleteAllDecodeInfo     
// 函数说明:释放ffmpeg结构体相关内存          
// 返 回 值: void     
//************************************  
void AACPlay::deleteAllDecodeInfo()
{
	// Close file	///释放申请的输出buffer
	if(m_pDecodeFrameBuff)
	{
		av_free(m_pDecodeFrameBuff);
		m_pDecodeFrameBuff = NULL;
	}
	if(m_pDecodeTempOutBuff)
	{
		av_free(m_pDecodeTempOutBuff);
		m_pDecodeTempOutBuff = NULL;
	}
	if(m_pDecodeSwrCtx)
	{
		///保留 重采样模块需要用,现在是每次都申请,后续可改为一次初始 多次使用最后释放
		swr_free(&m_pDecodeSwrCtx);
		m_pDecodeSwrCtx = NULL;
	}
	if(m_pDecodeFrame)
	{
		av_frame_free(&m_pDecodeFrame);
		m_pDecodeFrame = NULL;
	}
	if(m_pDecodeCodecParserCtx)
	{
		av_parser_close(m_pDecodeCodecParserCtx);
		m_pDecodeCodecParserCtx = NULL;
	}
	
	// Close the codec	///释放获取的解码指针
	if(m_pDecodeCodecCtx)
	{
		avcodec_close(m_pDecodeCodecCtx);
		av_free(m_pDecodeCodecCtx);
		m_pDecodeCodecCtx = NULL;
	}
	// Close the video file	释放格式化指针
	if(m_pDecodeFormatCtx)
	{
		avformat_free_context(m_pDecodeFormatCtx);
		m_pDecodeFormatCtx = NULL;
	}
	
	m_decodePacket.data = NULL;
	m_decodePacket.size = 0;
	m_nAudioStreamIndex=-1;
	m_nDecodeBuffSize=0;
	m_decodeCodecID=AV_CODEC_ID_NONE;			///当前解码时选择id	
	m_nDecodeFrameCount=0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值