基于ffmpeg的音频转换器pcm转amr(8000HZ)

根据近期项目中应用需要,需要将udp协议承载的 pcm(44100HZ,1024bit)媒体流,转换成amr格式音频流并以rtp协议发送出去。ffmpeg强大的媒体处理功能,再次得到了淋漓尽致的体现,不多说了,直接上代码,希望对大家有帮助

#include <stdio.h> 
#include <time.h>
#include <winsock2.h>
#include <windows.h>
#include <sys/stat.h>
#include <process.h>   
#pragma comment (lib, "ws2_32.lib")

//_declspec(dllimport) int add(int, int);
//_declspec(dllimport) int sub(int, int);

#define AMR_MAGIC_NUMBER      "#!AMR\n" 
#define MAX_PATH 256
#define PCM_BUF_LEN		1024
#define CACHE_PCM_LEN		10240

#pragma pack(1)
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;  
#pragma pack(push | pop)
int dc_rtp_port;
int local_udp_port;
int dc_udp_port;
int amr_sample_rate;
int end_task_flag;
char dc_ip[MAX_PATH];
char local_ip[MAX_PATH];
int audio_header_flag;
#define UDP_BUF_LEN 2048


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};


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_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, "ab+");
        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 (p_data == NULL)
    {
        return 0;
    }
    
    bytes += len;
    fwrite(p_data, sizeof( unsigned char), len, fpamr);
    fclose(fpamr);
    //printf("bytes = %d\n",bytes);
    return bytes;
}

int gettimeofday(struct timeval *tp, void *tzp)
{
	time_t 					clock;
  	struct 	tm 				tm;
	SYSTEMTIME 				wtm;
  	GetLocalTime			(&wtm);
	
	tm.tm_year  = wtm.wYear - 1900;
  	tm.tm_mon   = wtm.wMonth - 1;
	tm.tm_mday  = wtm.wDay;
  	tm.tm_hour  = wtm.wHour;
  	tm.tm_min   = wtm.wMinute;
	tm.tm_sec   = wtm.wSecond;
  	tm.tm_isdst = -1;
  	clock = mktime(&tm);
	tp->tv_sec = clock;
  	tp->tv_usec = wtm.wMilliseconds * 1000;
  	return (0);
}

int send_rtp()
{
	WSADATA 				wsaData;
    WORD 					sockVersion = MAKEWORD(2,2);
	struct sockaddr_in 		remoteAddr;
	int 					serSocket;
	struct sockaddr_in 		serAddr; 
    int 					cnt=0;
	int						ret=0;
    int 					nAddrLen = sizeof(remoteAddr);   
	unsigned char 			recvData[UDP_BUF_LEN];
	unsigned char 			rtpData[UDP_BUF_LEN];
	unsigned char			rtpHeader[13]={0x80,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0};
	unsigned short 			seq_no = 0;
	unsigned short			seq = 0;
	int 					pktsize;

	unsigned  long 			timestamp = 0;
	unsigned  long 			ts = 0;
	int						bytes = 0;

	printf("Listening on port %d\n",local_udp_port);      
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{  
        return 0;  
    }  
  
    serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   
    if(serSocket == INVALID_SOCKET)
	{  
        printf("socket error !");  
        return 0;  
    }      
    serAddr.sin_family = AF_INET;  
    serAddr.sin_port = htons(dc_udp_port);  
    serAddr.sin_addr.s_addr = inet_addr(local_ip);
    if(bind(serSocket, (SOCKADDR *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
	{  
        printf("bind error !");  
        closesocket(serSocket);  
        return 0;  
    } 
	/*ret = udpsocket_write(serSocket,local_ip,local_udp_port, pcm_header, sizeof(pcm_header));
	if(ret<0)
	{
		printf("udpsocket_write fail!\n");
	}*/
	//printf("send pcm header success!\n");
	while (1&&!end_task_flag)
	{
		memset(recvData, 0, UDP_BUF_LEN);
		memset(rtpData, 0, UDP_BUF_LEN);
		pktsize = recvfrom(serSocket, recvData, UDP_BUF_LEN, 0, (SOCKADDR *)&remoteAddr, &nAddrLen);
		if(pktsize<=0)
		{
			continue;
		}		
		//bytes = write_amr_file("test.amr",recvData,pktsize);
		
		seq = htons(seq_no);
		ts= htonl(timestamp);

		memcpy(rtpData,rtpHeader,13);
		memcpy(rtpData+2,&seq,2);
		memcpy(rtpData+4,&ts,4);
		//rtpData[12] = 0xf0;
		memcpy(rtpData+13,recvData,pktsize);
		
		seq_no+=1;				
		timestamp += 160;		

		if(seq_no >=0xffff)
		{
			seq_no = 0;
		}
		
		if(timestamp >= 0xffffffff)
		{
			timestamp = 0;
		}
		//char *rtp_data = &(rtpData+12);
		//rtpData[12] =0xf0;
		
		ret = udpsocket_write(serSocket,dc_ip, dc_rtp_port, rtpData, pktsize+13);
		if(ret<0)
		{
			printf("udpsocket_write fail!\n");
		}
		Sleep(10);
	}
	 
}
/*  
int udp_parser()
{
	WSADATA 				wsaData;
    WORD 					sockVersion = MAKEWORD(2,2);
	struct sockaddr_in 		remoteAddr;
	int 					serSocket;
	struct sockaddr_in 		serAddr; 
    int 					cnt=0;
	int						ret=0;
    int 					nAddrLen = sizeof(remoteAddr);   
    int 					parse_rtp=1; 
	char 					recvData[10000];
	char 					parseData[10000];
	
    printf("Listening on port %d\n",local_rtp_port);      
	if(WSAStartup(sockVersion, &wsaData) != 0)
	{  
        return 0;  
    }  
  
    serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   
    if(serSocket == INVALID_SOCKET)
	{  
        printf("socket error !");  
        return 0;  
    }      
    serAddr.sin_family = AF_INET;  
    serAddr.sin_port = htons(local_rtp_port);  
    serAddr.sin_addr.s_addr = inet_addr(local_ip);
    if(bind(serSocket, (SOCKADDR *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
	{  
        printf("bind error !");  
        closesocket(serSocket);  
        return 0;  
    }  
	 
    while (1&&!end_task_flag)
	{
		int pktsize = recvfrom(serSocket, recvData, 10000, 0, (SOCKADDR *)&remoteAddr, &nAddrLen);
		if(audio_header_flag==0)
		{
			ret = udpsocket_write(serSocket, local_ip, local_udp_port, "#!AMR\n", 6);
			audio_header_flag=1;
		}
		if(pktsize>6)
		{
			int rtp_header_size = sizeof(RTP_FIXED_HEADER);
			char *rtp_data = recvData+rtp_header_size;
			int rtp_data_size = pktsize-rtp_header_size;
			memcpy((void *)&parseData,rtp_data,rtp_data_size); 
			
			ret = udpsocket_write(serSocket,local_ip, local_udp_port, parseData, rtp_data_size);
			if(ret<0)
			{
				printf("udpsocket_write fail!\n");
			}
		}        
    }
}
*/
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
	{	
		 dc_rtp_port = GetPrivateProfileInt("音频转换器信息","DC_RTP_PORT",20001,inifilepath);
		 local_udp_port = GetPrivateProfileInt("音频转换器信息","LOCAL_UDP_PORT",20002,inifilepath);
		 dc_udp_port	= GetPrivateProfileInt("音频转换器信息","DC_UDP_PORT",20003,inifilepath); 
		 amr_sample_rate = GetPrivateProfileInt("音频转换器信息","AMR_SAMPLE_RATE",8000,inifilepath);
		if (GetPrivateProfileString("音频转换器信息",
									"DC_IP",
									"\0",
									(char*)dc_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 -acodec amr_nb -ab 12.2k -ar %d -ac 1 -f amr udp://%s:%d", 
			local_ip,local_udp_port+1,amr_sample_rate,local_ip,dc_udp_port);
	printf("systemStateName=%s\n",systemStateName);
	system(systemStateName);
}

void *end_task(void *param)
{
    getchar();
    end_task_flag= 1;	
    printf("audio_converter_pcm_to_amr exit successfully\n");
	exit(1);
}

void * deal_pcm_stream(void * arg)
{
	int 					serSocket;
	char 					recvData[CACHE_PCM_LEN]={0};
	char 					cacheData[CACHE_PCM_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;
	int						ret;

	int						ffmpeg_rec_pcm_port = local_udp_port + 1;
	
	
	serSocket = udpsocket_setup_server(local_udp_port);
	if(serSocket < 0)
	{
		printf("make_final_pcm_stream serSocket setup fail\n");
		return NULL;
	}

	ret = udpsocket_write(serSocket,local_ip,ffmpeg_rec_pcm_port, pcm_header, sizeof(pcm_header));
	if(ret<0)
	{
		printf("udpsocket_write fail!\n");
	}
	
    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;
			}
			
			memcpy(cacheData,&recvData[5],rcv_data_len-5);

			result = udpsocket_write(serSocket,local_ip, ffmpeg_rec_pcm_port, cacheData, rcv_data_len-5);
			if(result<0)
			{
				printf("make_final_pcm_stream send 1024 byte pcm fail!\n");
				continue;
			}
			
		}
	}
	return NULL;
}


int main()
{
	
	char * pstr = "start thread";
	GetIni();
	printf("local_ip=%s\n dc_rtp_port=%d\n dc_udp_port=%d\n amr_sample_rate=%d\n dc_ip=%s\n",
		local_ip,dc_rtp_port,dc_udp_port,amr_sample_rate,dc_ip);

	_beginthread(ffmpeg_convert_audio,0,pstr); 
	_beginthread(end_task,0,pstr);
	Sleep(500);
	_beginthread(deal_pcm_stream,0,pstr);	
	send_rtp();	

	return 0;
}

相关工程文件已上传

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值