基于ffmpeg的音频转换器-rtp承载的amr转换为pcm音频流

根据近期项目中应用需要,需要将rtp协议承载的 amr(8kHZ)媒体流,转换成pcm格式音频流并以udp协议发送出去。ffmpeg强大的媒体处理功能,再次得到了淋漓尽致的体现,不多说了,直接上代码,记录一下

#include <stdio.h> 
#include <stdlib.h>
#include <WinSock2.h>
#include <windows.h>
#include <sys/stat.h>
#include <process.h>  
#include <time.h> 

//_declspec(dllimport) int add(int, int);
//_declspec(dllimport) int sub(int, int);
#pragma comment(lib,"ws2_32.lib")

#define AMR_MAGIC_NUMBER      "#!AMR\n" 
#define MAX_PATH 256
#define	AMR_FRAME_LENGTH		32
#define PCM_BUF_LEN		1024
#define CACHE_PCM_LEN		10240
typedef struct RTP_FIXED_HEADER{  
    /* byte 0 */  
    unsigned char csrc_len:4;       /* expect 0 */  
    unsigned char extension:1;      /* expect 1 */  
    unsigned char padding:1;        /* expect 0 */  
    unsigned char version:2;        /* expect 2 */  
    /* byte 1 */  
    unsigned char payload:7;  
    unsigned char marker:1;        /* expect 1 */  
    /* bytes 2, 3 */  
    unsigned short seq_no;              
    /* bytes 4-7 */  
    unsigned  long timestamp;          
    /* bytes 8-11 */  
    unsigned long ssrc;            /* stream number is used here. */  
} RTP_FIXED_HEADER;  

int local_rtp_port;
int local_udp_port;
int local_pcm_port;
int remote_port;
int pcm_sample_rate;
int end_task_flag;
char remote_ip[MAX_PATH]={0};
char local_ip[MAX_PATH]={0};
int audio_header_flag;

int udpsocket_setup_server(int serv_port)
{
    const int   on = 1;             /* for setsockopt() */
    const int   newon = 512000;
    int         optlen = 4;
    int         optlen2 = 4;
	int 		sock = -1;
    
	char 		set = 1;  
    WSADATA wsd;           //初始化信息
    
    struct sockaddr_in      saddr;

	if (WSAStartup(MAKEWORD(2,2),&wsd) != 0) 
	{/*进行WinSocket的初始化,        windows 初始化socket网络库,申请2,2的版本,windows socket编程必须先初始化。*/       
	 	printf( "WSAStartup Error = %d" , WSAGetLastError() );        
		return 0;    
	}
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(serv_port);
    saddr.sin_addr.s_addr = inet_addr(local_ip);        
	
    //setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(int));
	
    if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
    {
		printf("socket (AF_INET, SOCK_DGRAM, 0)) failed!\n");
        return (-1);
    }
	if (getsockopt (sock, SOL_SOCKET, SO_RCVBUF,(char*) &on, (int *)&optlen) < 0)
    {
        closesocket(sock);
        return (-1);
    }

    if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF,(char*) &newon, optlen2) < 0)
    {
        closesocket(sock);
        return (-1);
    }
    if (getsockopt (sock, SOL_SOCKET, SO_RCVBUF,(char*) &on, (int *)&optlen) < 0)
    {
        closesocket(sock);
        return (-1);
    }
   
    if (bind (sock, (struct sockaddr *)&saddr, sizeof (saddr)) < 0)
    {
		printf("bind (sock, (struct sockaddr *)&saddr, sizeof (saddr)) failed!\n");
        closesocket(sock);
        return (-1);
    }

    return sock;
}

int udpsocket_read(int sockfd, char *strip, int *serv_port, char *pbuf, int *len)
{
	long int 			    msgsize;
    struct sockaddr_in     saddr;
	int					    saddrlen = sizeof (struct sockaddr_in);

	msgsize = recvfrom(sockfd, (char *)pbuf, *len, 
						0, (struct sockaddr *)&saddr,
						(int  *)&saddrlen);
	if (0 >= msgsize)
	{
		//printf("msgsize %d \n",msgsize);
		return -1;
    }

    /** If the input param is a pointer then the
		value can not be straight away assigned, it needs to be copied -- Rajen **/
	strcpy(strip,inet_ntoa(saddr.sin_addr));
    /** strip=inet_ntoa(saddr.sin_addr); **/

	*serv_port=ntohs(saddr.sin_port);
	*len = msgsize;	/* return actually recv len */

	return 1;
}


int udpsocket_write(int sockfd, char *strip, int serv_port, char *pbuf, int len)
{
    struct sockaddr_in      saddr;
    unsigned long            serv_ipaddr;
	
    memset(&saddr, 0, sizeof(struct sockaddr_in));

    if ((serv_ipaddr = inet_addr(strip)) == -1)
    {
		printf("Invalid IP address: %s\n",strip);
        return -1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(serv_port);
	saddr.sin_addr.s_addr = inet_addr(strip);

    if (sendto(sockfd, pbuf, len, 0, (struct sockaddr *)&saddr,
               sizeof( struct sockaddr_in)) < 0)
    {
        return -1;
    }

    return 1;
}

void udpsocket_close_server(int sock)
{
	closesocket(sock);
	return ;
}

int write_wav_file(char *file_name, char *p_data, int len)
{
    FILE*  fpwav = NULL;

	static char	pcm_header[] = 
	{ 'R','I','F','F', 		 /* 0x52,0x49,0x46,0x46 RIFF */
	  0x24,0x00,0x00,0x00, /* 0xff,0xff,0xff,0xff,RIFF_SIZE or 0*/
	  'W','A','V','E', 		 /* WAVE */
	  'f','m','t',' ', 		 /* fmt  */
	  0x10,0x00,0x00,0x00, /* FORMAT_SIZE */
	  0x01,0x00,            /* FORMATTAG */
	  0x01,0x00,            /* CHANNELS */
	  0x44,0xac,0x00,0x00, /* SamplesPerSec */ /* 44100 */
	  0x88,0x58,0x01,0x00, /* AvgBytesPerSec */ /* 88200 */   
	  0x02,0x00,            /* BlockAlign */ /*2 */
	  0x10,0x00,            /* BitsPerSample */ /*  16 */
	  'd','a','t','a', 		 /*LIST or data*/
	  0x00,0x00,0x00,0x00};
	//printf("in function WirteWavFile len:%d\n", len);

	fpwav = fopen(file_name, "rb+");
	if (fpwav == NULL)
    {
		fpwav = fopen(file_name, "ab+");
        if (fpwav == NULL)
        {
           return 0;
        }
		fwrite(pcm_header,1,sizeof(pcm_header),fpwav);
    } 
	else
	{
		fclose(fpwav);
		fpwav = fopen(file_name, "ab+");
	}
	
	fwrite(p_data, 1, len, fpwav);
    fclose(fpwav);

	
   
    return 1; 
}

int write_amr_file(char *file_name, unsigned char *p_data, int len)
{
    //static S8bit       fname[256] = "test.amr";
    int                 bytes = 0;
    FILE                *fpamr = NULL;

	fpamr = fopen(file_name, "rb");
	if (fpamr == NULL)
    {
		fpamr = fopen(file_name, "wb+");
        if (fpamr == NULL)
        {
           return 0;
        }
        /* write magic number to indicate single channel AMR file storage format */
        bytes = fwrite(AMR_MAGIC_NUMBER, sizeof( unsigned char), strlen(AMR_MAGIC_NUMBER), fpamr);
	    //printf("fpamr is NULL!\n");
        //return 0;
    } 
	else
	{
		fclose(fpamr);
		fpamr = fopen(file_name, "ab+");
	}

#if 0
    if (NULL == fopen(file_name, "r"))
    {
        fpamr = fopen(file_name, "wb");
        if (fpamr == NULL)
        {
           return 0;
        }
        /* write magic number to indicate single channel AMR file storage format */
        bytes = fwrite(AMR_MAGIC_NUMBER, sizeof(char), strlen(AMR_MAGIC_NUMBER), fpamr);
    }
    else
    {
        fpamr = fopen(file_name, "ab");
    }
#endif
    if (p_data == NULL)
    {
        return 0;
    }
    
    bytes += len;
    fwrite(p_data, sizeof( unsigned char), len, fpamr);
    fclose(fpamr);
    
    return bytes;
}

int make_final_pcm_stream()
{
	int 					serSocket;
	char 			recvData[CACHE_PCM_LEN]={0};
	char 			cacheData[CACHE_PCM_LEN]={0};
	char 			finalData[PCM_BUF_LEN]={0};
	char					src_ip[20] = {0};
	int						src_port = 0;
	int 					rcv_data_len = 0;
	int						cache_buf_len = 0;
	int 					result = 0;
	struct timeval 		select_time;
	struct fd_set			sock_set;
	

	serSocket = udpsocket_setup_server(local_pcm_port);
	if(serSocket < 0)
	{
		printf("make_final_pcm_stream serSocket setup fail\n");
		return -1;
	}
    while (1&&!end_task_flag)
	{
		select_time.tv_sec  = 0;
		select_time.tv_usec = 10000;

		FD_ZERO(&sock_set);  
		FD_SET(serSocket, &sock_set);

		if((result = select(serSocket+1, &sock_set, (fd_set*)NULL, (fd_set*)NULL, &select_time)) > 0)
		//if( udpsocket_read(serSocket,src_ip,&src_port,recvData,&rcv_data_len)>0)
		{
			rcv_data_len = CACHE_PCM_LEN;
			memset(recvData, 0, rcv_data_len);
			
			if(udpsocket_read(serSocket,src_ip,&src_port,recvData,&rcv_data_len)<0)
			{
				continue;
			}
			if(rcv_data_len==78)
			{
				continue;
			}
			memcpy(&cacheData[cache_buf_len],recvData,rcv_data_len);
			
			cache_buf_len+=rcv_data_len;
			
			//write_wav_file("test0.wav",recvData,rcv_data_len);
			//printf("rcv_data_len=%d\n",rcv_data_len);

			if(cache_buf_len>CACHE_PCM_LEN)
			{
				cache_buf_len = 0;
			}
			
			if(cache_buf_len>PCM_BUF_LEN)
			{
				memcpy(finalData,cacheData,PCM_BUF_LEN);
				
				cache_buf_len -= PCM_BUF_LEN;

				memcpy(cacheData,&cacheData[PCM_BUF_LEN],cache_buf_len);
				
				result = udpsocket_write(serSocket,remote_ip, remote_port, finalData, PCM_BUF_LEN);
				if(result<0)
				{
					printf("make_final_pcm_stream send 1024 byte pcm fail!\n");
					continue;
				}
				//write_wav_file("test.wav",finalData,PCM_BUF_LEN);
			}
		}
	}
	return 1;
}
  
int amr_rtp_parser()
{
	
	int 					serSocket;
    int 					cnt=0;
	int						ret=0;
    int 					parse_rtp=1; 
	char 					recvData[100]={0};
	char 					parseData[100]={0};
	char					src_ip[20] = {0};
	int						src_port = 0;
	int						rcv_buf_len = 0;
	int 					rtp_header_size = sizeof(RTP_FIXED_HEADER);
	int						msg_len;
	struct timeval 		select_time;
	struct fd_set			sock_set;
	
    printf("Listening on port %d\n",local_rtp_port);      
	 

	serSocket = udpsocket_setup_server( local_rtp_port);
	if(serSocket < 0)
	{
		printf("serSocket setup fail\n");
	}
    while (1&&!end_task_flag)
	{
		select_time.tv_sec  = 0;
		select_time.tv_usec = 5000;

		FD_ZERO(&sock_set);  
		FD_SET(serSocket, &sock_set);

		if((ret = select(0, &sock_set, (fd_set*)NULL, (fd_set*)NULL, &select_time)) > 0)
		{
			msg_len = 100;
			memset(recvData, 0, msg_len); 
			//memset((void*)p_client_mes_req_st,0,sizeof(mes_req_st));
			ret = udpsocket_read(serSocket,src_ip,&src_port,recvData,&msg_len);
			if(ret<0)
			{
				continue;
			}
			if(audio_header_flag==0)
			{
				//ret = udpsocket_write(serSocket, remote_ip, remote_port, "#!AMR\n", 6);
				ret = udpsocket_write(serSocket, local_ip, local_udp_port, "#!AMR\n", 6);
				audio_header_flag=1;
			}
			//printf("recvData[rtp_header_size]=%x\n",recvData[rtp_header_size]);
			if(recvData[rtp_header_size]==0xf0)
			{			
				if(0x3c==recvData[rtp_header_size+1])
				{
					/*frame_cnt=1*/
					//printf("frame_cnt=1;");
					memcpy(parseData,&recvData[rtp_header_size+1],AMR_FRAME_LENGTH); 
					
					ret = udpsocket_write(serSocket,local_ip, local_udp_port, parseData, AMR_FRAME_LENGTH);
					//ret = udpsocket_write(serSocket,remote_ip, remote_port, parseData, AMR_FRAME_LENGTH);
					if(ret<0)
					{
						printf("udpsocket_write fail!\n");
					}
				}
				else if(0xbc == recvData[rtp_header_size+1] && 0x3c == recvData[rtp_header_size+2])
				{
					/*frame_cnt=2*/
					memcpy(parseData,&(recvData[rtp_header_size+2]),AMR_FRAME_LENGTH);
					//ret = udpsocket_write(serSocket,local_ip, local_udp_port, parseData, AMR_FRAME_LENGTH);
					parseData[AMR_FRAME_LENGTH] = 0x3c;
					memcpy(&parseData[AMR_FRAME_LENGTH+1],&(recvData[rtp_header_size+2+AMR_FRAME_LENGTH]),AMR_FRAME_LENGTH-1);
					//parseData[0]=0x3c;
					//memcpy(&parseData[1],&(recvData[rtp_header_size+2+AMR_FRAME_LENGTH]),AMR_FRAME_LENGTH-1);
					ret = udpsocket_write(serSocket,local_ip, local_udp_port, parseData, AMR_FRAME_LENGTH*2);
					if(ret<0)
					{
						printf("udpsocket_write fail!\n");
					}
					//write_amr_file("1.amr",parseData,AMR_FRAME_LENGTH*2);
				}
			}
		}
    }
	return 1;
}

int GetIniFullPath(char * temppath)
{
    char sPath[MAX_PATH];      //临时路径
    char path[MAX_PATH];       //可执行文件的全路径,包括可执行文件名
    char exepath[MAX_PATH];    //配置文件的路径,包括配置文件文件名
    char inipath[MAX_PATH];    //配置文件的路径,包括配置文件文件名
    int iPosition;
    int  i = 0;

    __try
    {
        memset(sPath, 0, sizeof(sPath));
        memset(path, 0, sizeof(path));
        memset(exepath, 0, sizeof(exepath));
        memset(inipath, 0, sizeof(inipath));

        GetModuleFileName(NULL, path, MAX_PATH);
		
		sprintf_s(sPath, sizeof(sPath), "%s", path);
		
        memcpy(sPath,path, MAX_PATH );

        for (i = sizeof(sPath); i > 0; i--)
        {
            if (sPath[i - 1] == '\\')
            {
                iPosition = i;
                break;
            }
        }

        memcpy(exepath, sPath, iPosition);
        sprintf_s(inipath, sizeof(inipath), "%sconifg.ini", exepath);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        return 0;
    }

    memcpy(temppath, inipath, sizeof(inipath));
	printf("inipath=%s\n",&inipath);
    return 1;
}


void GetIni()
{
	char inifilepath[MAX_PATH];
	char buffini[80];
	memset(inifilepath,0, sizeof(inifilepath));
	GetIniFullPath(inifilepath);
	
	__try
	{	
		 local_rtp_port = GetPrivateProfileInt("音频转换器信息","LOCAL_RTP_PORT",20001,inifilepath);
		 local_udp_port = GetPrivateProfileInt("音频转换器信息","LOCAL_UDP_PORT",20002,inifilepath);
		 remote_port	= GetPrivateProfileInt("音频转换器信息","REMOTE_PORT",20003,inifilepath); 
		 pcm_sample_rate = GetPrivateProfileInt("音频转换器信息","PCM_SAMPLE_RATE",44100,inifilepath);
		 local_pcm_port = local_udp_port + 100;
		if (GetPrivateProfileString("音频转换器信息",
									"REMOTE_IP",
									"\0",
									(char*)remote_ip,
									MAX_PATH,
									(const char *)inifilepath) == 0)
		{
			printf("GetIni, Error");
		}
		if (GetPrivateProfileString("音频转换器信息",
									"LOCAL_IP",
									"\0",
									(char*)local_ip,
									MAX_PATH,
									(const char *)inifilepath) == 0)
		{
			printf("GetIni, Error");
		}
        
	}
	__except(EXCEPTION_EXECUTE_HANDLER )
	{
		printf("GetIni, Error:%d",GetLastError());
	}
}

void * ffmpeg_convert_audio(void * arg)
{
	char systemStateName[256] = {0};
	sprintf_s(systemStateName, sizeof(systemStateName), "ffmpeg -re -i udp://%s:%d -f s16le -acodec pcm_s16le -ar %d -ac 1  udp://%s:%d", 
			local_ip,local_udp_port,pcm_sample_rate,local_ip,local_pcm_port);
	//sprintf_s(systemStateName, sizeof(systemStateName), "ffmpeg -re -i udp://%s:%d -acodec aac -f flv rtmp://%s:1935/live/0", 
	//		local_ip,local_udp_port,local_ip);
	printf("systemStateName=%s\n",systemStateName);
	system(systemStateName);
}

void *end_task(void *param)
{
    getchar();
    end_task_flag= 1;	
    printf("the test will go to end\n");
	exit(1);
}

int main()
{
	
	char * pstr = "start thread";
	GetIni();
	printf("local_ip=%s,local_port=%d\n,remote_port=%d\n,pcm_sample_rate=%d\n,remote_ip=%s\n",
		local_ip,local_rtp_port,remote_port,pcm_sample_rate,remote_ip);
	//先打开ffmpeg
	_beginthread(ffmpeg_convert_audio,0,pstr); 
	_beginthread(end_task,0,pstr);
    //由于项目特殊需求,在每个pcm音频包发出去大小为1024字节。
	_beginthread(make_final_pcm_stream,0,pstr);
    //去除rtp头,amr音频解析为纯udp流
	_beginthread(amr_rtp_parser,0,pstr);	
	getchar();
	return 0;
}

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值