您当前的位置: 首页 > 

qianbo_insist

暂无认证

  • 0浏览

    0关注

    399博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

ffmpeg rtp传输使用

qianbo_insist 发布时间:2021-05-25 06:24:35 ,浏览量:0

1 ffmpeg rtp

   ffmpeg估计已经成为多媒体 流媒体开发的必备工具,编解码不可缺少的伙伴,rtp协议本身是非常优良的协议,刚进入协议编程的伙伴可以使用ffmpeg的rtp编程来入门,抓包,这里是示例,同时讲一下原理。

2 简单使用 2.1 包含头文件

别忘了加上extern “C”,ffmpeg是纯c程序

extern "C" {
#include 
#include 
}
2.2 命令行

看指令 //推RTP //ffmpeg - re - i cw.ts - vcodec copy - acodec copy - f rtp_mpegts rtp://238.123.46.66:8001 推rtp //推UDP //ffmpeg - re - i cw.ts - vcodec copy - acodec copy - f mpegts udp://238.123.46.66:8001 推udp

2.3 查找编码器
if (v != NULL)
{
	//查找编码器
	AVCodec *cv = avcodec_find_encoder(AV_CODEC_ID_H264);
	//创建流
	m_st_v = avformat_new_stream(m_fmtctx, cv);
	//从context拷贝codecpar
	avcodec_parameters_from_context(m_st_v->codecpar, v);
}
2.4 设置参数

   RTP 协议中,最需要设置的是payload和ssrc,这是唯一指定一路流的标识,除了源端口和源IP,ssrc是真正指明自己是哪一路的,DHCP或者移动网络中,IP地址和端口号可能会变化,不能使用这种方式来指明唯一的一路流,实际上,应该使用信令服务器配合sdp协议来获取ssrc和其他参数,sip协议和rtsp协议等都是信令的作用。    为什么要自己设置ssrc和payloadtype?你可以根据服务器返回来设定这些值,尤其是经过解析sdp协议来拿到payload,不然仅仅是一个值,怎么可能知道到底是什么编码,所以sdp协议名字叫做会话描述协议。

	av_opt_set_int(m_fmtctx->priv_data, "payload_type", 96, 0);
	av_opt_set_int(m_fmtctx->priv_data, "ssrc", ssrc, 0);
2.4 发送

   调整时间戳发送,pts和dts分别意义为呈现时间戳 – present 和解码时间戳–decode,实际上,这个时间戳不要较真,不用拿着一知半解的函数算来算去,记住这个时间戳就是真实的时间而已,假定有一个静音检测,一段时间没有声音,千万别按照很多例子,依然按照死的公式计算时间

current = 当前时间 time[n] 表示第n帧时间 time[1] = 第一帧时间 time[2] = current - time[1]

   其实pts、dts可以放置真正的当前时间,本来就是指明当前帧的时间的,播放器应该拿到第一帧关键时间戳后计算后面相对时间就行。就这么简单 ,不要被眼花缭乱的时间计算公式给蒙了,但是这里要说明RTP时间如视频发送出去实际上是要使用90000基数的,为什么要用这个基数呢?因为计算帧数涉及到整除的问题,这个90000是恰到好处而已。

	void send(AVPacket * pkt)
	{
		//写文件头
		pkt->stream_index = m_st_v->index;
		pkt->pts = av_rescale_q(pkt->pts, m_p_v->time_base, m_st_v->time_base);
		pkt->dts = av_rescale_q(pkt->dts, m_p_v->time_base, m_st_v->time_base);
		pkt->pos = -1;
		av_interleaved_write_frame(m_fmtctx, pkt);
		av_packet_free(&pkt);
	}
3 完整class,实践出真知
#pragma once
#if 1
extern "C" {
#include 
#include 
}
#define HASH_PRIME_MIDDLE 10001531
static int hash_add(const char* key, int prime)
{
	int hash, i;
	int len = (int)strlen(key);
	for (hash = len, i = 0; i name,
			rtp);
		AVDictionary *options = NULL;
		av_dict_set(&options, "buffer_size", "102400", 0); //设置缓存大小,1080p可将值调大
		av_dict_set(&options, "send_buffer_size", "102400", 0); //设置缓存大小,1080p可将值调大
		av_dict_set(&options, "pkt_size", "1400", 0);
		//96 h264
		av_opt_set_int(m_fmtctx->priv_data, "payload_type", 96, 0);
		av_opt_set_int(m_fmtctx->priv_data, "ssrc", ssrc, 0);
		avio_open2(&m_fmtctx->pb, rtp,
			AVIO_FLAG_WRITE, NULL, &options);
		//初始化AVStream
		if (v != NULL)
		{
			//查找编码器
			AVCodec *cv = avcodec_find_encoder(AV_CODEC_ID_H264);
			m_st_v = avformat_new_stream(m_fmtctx, cv);
			avcodec_parameters_from_context(m_st_v->codecpar, v);
		}
		if (a != NULL)
		{
			AVCodec *ca = avcodec_find_encoder(AV_CODEC_ID_AAC);
			m_st_a = avformat_new_stream(m_fmtctx, ca);
			avcodec_parameters_from_context(m_st_a->codecpar, a);
		}
		avformat_write_header(m_fmtctx, NULL);
		char sdp[256];
		av_sdp_create(&m_fmtctx, 1, sdp, sizeof(sdp));
		//FILE * fp = fopen("c:\\test.sdp", "wb");
		//fwrite(sdp, 1, strlen(sdp), fp);
		//fclose(fp);
		printf("%s\n", sdp);
		return 0;
	}
	//设置AVCodecContext编码参数    
	void send(AVPacket * pkt)
	{
		//写文件头
		pkt->stream_index = m_st_v->index;
		pkt->pts = av_rescale_q(pkt->pts, m_p_v->time_base, m_st_v->time_base);
		pkt->dts = av_rescale_q(pkt->dts, m_p_v->time_base, m_st_v->time_base);
		pkt->pos = -1;
		av_interleaved_write_frame(m_fmtctx, pkt);
		av_packet_free(&pkt);

	}
	void UnInit()
	{
		//销毁资源
		if (!(m_fmtctx->oformat->flags & AVFMT_NOFILE))
			avio_close(m_fmtctx->pb);
		avformat_free_context(m_fmtctx);
	}
};
#endif

后面会继续写手动发送和接收rtp包

关注
打赏
1663161521
查看更多评论
立即登录/注册

微信扫码登录

0.0374s