根据近期项目中应用需要,需要将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;
}
相关工程文件已上传