FFMPEG API函数根据SDP文件接收RTP媒体流

背景

版本ffmpeg 3.3.3;使用 FFmpeg实时接收rtp 音频和视频流,并生成视频文件。

在网上查阅了大量资料,基本上都是使用命令行来接收rtp媒体流的,由于项目中不得不使用ffmpeg接收RTP实时流。因此花了不少时间研究。

ffmepg 默认是不打开rtp协议的,需要添加白名单后,并根据sdp文件来接收rtp媒体流。sdp文件也很费劲,刚开始不明白sdp文件是啥,具体含义也不知道,研究半天才搞懂大概。

添加白名单时一定要申请单独的内存块,我在这个坑里痛苦了很久,之前直接赋值,老是崩溃,不明原因。后来经高人指点,幡然醒悟,白名单在avformat_close_input中会进行free,必须要申请内存才行。

废话不多说,直接上代码

    //初始化输入上下文    
    AVFormatContext 	*p_ifmt_ctx_v = avformat_alloc_context();
	AVFormatContext		*p_ifmt_ctx_a  = avformat_alloc_context();
    AVInputFormat 		*p_ifmt_v = NULL;
	AVInputFormat 		*p_ifmt_a = NULL;
    eU8					buffer[1280] = {0};
	eU8					port_v[10] = {0};
	eU8					port_a[10] = {0};
	eU8					sdp_file_name[128] = {0};
	eU8					sdp_file_name_a[128] = {0};
	FILE   				*fp = NULL;

    
    p_ifmt_ctx_v ->flags |= AVFMT_NOFILE;
    //添加白名单,这里很重要,如果不申请内存,在avformat_close_input中会宕
	p_ifmt_ctx_v ->protocol_whitelist = av_malloc(sizeof("file,udp,rtp"));
	memcpy(p_ifmt_ctx_v ->protocol_whitelist,"file,udp,rtp",sizeof("file,udp,rtp"));
	
	p_ifmt_ctx_a ->flags |= AVFMT_NOFILE;
    //添加白名单,这里很重要,如果不申请内存,在avformat_close_input中会宕
	p_ifmt_ctx_a ->protocol_whitelist = av_malloc(sizeof("file,udp,rtp"));
	memcpy(p_ifmt_ctx_a ->protocol_whitelist,"file,udp,rtp",sizeof("file,udp,rtp"));

    //输入的文件格式为sdp
	p_ifmt_v = av_find_input_format("sdp");
	p_ifmt_a = av_find_input_format("sdp");

    av_register_all();
	avfilter_register_all();
	avformat_network_init(); 

    //生成sdp文件,ffmpeg根据sdp文件获取到ip地址和port,以及媒体格式信息
    sprintf(sdp_file_name, "%d", threadid);
	strcat(sdp_file_name,"-v");
	strcat(sdp_file_name,".sdp");
	
	fp = fopen(sdp_file_name,"wb+");
	
	if(fp ==NULL)
	{
		printf("cannot open file sdp_file_name=%s \n",sdp_file_name);
		
		return FAILURE;
	}
	sprintf(port_v,"%d",video_port);

	strcat(buffer,"v=0\r\n");
    //发送rtp流的源ip地址	
	strcat(buffer,"o=- 0 0 IN IP4 127.0.0.1\r\n");
	strcat(buffer,"s=video\r\n" );
    //接收rtp流的ip地址
	strcat(buffer,"c=IN IP4 127.0.0.1\r\n" );
	strcat(buffer,"t=0 0\r\n" );
	strcat(buffer,"a=tool:libavformat 57.71.100\r\n");
	strcat(buffer,"m=video ");
	strcat(buffer,"  ");
    // 接收rtp流的端口
	strcat(buffer,port_v);
    //98 代表的是媒体格式,即rtp头中携带的媒体格式,我这里的h264 格式类型为98
	strcat(buffer," RTP/AVP 98\r\n");
	strcat(buffer,"a=rtpmap:98 H264/90000\r\n");
		
	fprintf(fp,"%s\n",buffer);
	fclose(fp);

    if ((ret = avformat_open_input(&p_ifmt_ctx_v , sdp_file_name, p_ifmt_v , NULL)) != 0) 
	{
        printf( "Cannot open p_ifmt_ctx_v file %s\n",buffer);
		return -1;
    }
//收音频流的sdp文件
    memset(sdp_file_name_a,0,sizeof(sdp_file_name_a));
	memset(buffer,0,sizeof(buffer));
	sprintf(sdp_file_name_a, "%d", threadid);
	strcat(sdp_file_name_a,"-a");
	strcat(sdp_file_name_a,".sdp");
	
	fp = fopen(sdp_file_name_a,"wb+");
	
	if(fp ==NULL)
	{
		printf("cannot open file sdp_file_name_a=%s \n",sdp_file_name_a);
		
		return -1;
	}
	
	sprintf(port_a,"%d",audio_port);
	
	strcat(buffer,"v=0\r\n");	
	strcat(buffer,"o=- 0 0 IN IP4 127.0.0.1\r\n");
	strcat(buffer,"s=audio \r\n" );
	strcat(buffer,"c=IN IP4 127.0.0.1\r\n" );
	
	strcat(buffer,"t=0 0\r\n" );
	strcat(buffer,"a=tool:libavformat 57.71.100\r\n");
	strcat(buffer,"m=audio ");
	strcat(buffer,"  ");
	strcat(buffer,port_a);
    //这里是amr格式类型,rtp头中显示126,根据实际进行修改
	strcat(buffer," RTP/AVP 126\r\n");
	strcat(buffer,"a=rtpmap:126 AMR/8000/1\r\n");
	
	
	fprintf(fp,"%s\n",buffer);
	fclose(fp);

     if ((ret = avformat_open_input(&p_ifmt_ctx_a  , sdp_file_name_a, p_ifmt_a , NULL)) != 0) 
	{

        printf( "Cannot open p_ifmt_ctx_a  file %s\n",in_filename_a);
	
        return -1;
    }

这里就打开了端口开始接收rtp媒体流了,接下来打印一下媒体流的信息,代码如下:

    if ((ret = avformat_find_stream_info(p_ifmt_ctx_v, NULL)) < 0) 
	{
        printf( "Cannot find ifmt_ctx_v stream information\n");
		
        goto end;
    } 
	  
	
	if ((ret = avformat_find_stream_info(p_ifmt_ctx_a, NULL)) < 0) 
	{
        printf( "Cannot find ifmt_ctx_a stream information\n");

        goto end;
    }
	
	printf("===========Input Information================\n");
	av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
	av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);	
	printf("============================================\n");

至此,ffmpeg根据sdp文件来接收rtp媒体流完成,在此记录一下。

参考 ffmpeg监听和接收rtp音视频流_阳光的威威的博客-CSDN博客_ffmpeg 监听

你可能感兴趣的:(FFmpeg处理媒体流,音视频,ffmpeg,sdp)