rtp h264 发送和接收程序的问题

news2024/11/28 2:39:25

目的

为了自己写一个投屏协议,目前重新启用rtp协议,使用rtp协议直传效率最高,并且使用的是udp

ffmpeg 发送rtp

ffmpeg的rtp发送时一般把sps和pps放在一个包里面,写接收代码的时候要注意,在单包里面可以直接接收到两个,不过自己写的代码就不一样了,很多人喜欢把sps和pps 分开来发送,写错了,就会丢包

libx264 和 ffmpeg编码发送

直接使用libx264发送

int X264Encoder::Encode4RTP(unsigned char * szYUVFrame, bool &isKeyframe)
{
	int numPixels = m_param.i_width * m_param.i_height;
	m_pic.img.plane[0] = szYUVFrame;
	m_pic.img.plane[1] = szYUVFrame + numPixels;
	m_pic.img.plane[2] = szYUVFrame + numPixels * 5 / 4;
	m_pic.img.i_stride[0] = m_param.i_width;
	m_pic.img.i_stride[1] = m_param.i_width / 2;
	m_pic.img.i_stride[2] = m_param.i_width / 2;
	m_param.i_frame_total++;
	m_pic.i_pts = (int64_t)m_param.i_frame_total * m_param.i_fps_den;
	//dts赋值和pts相同的值
	m_pic.i_dts = m_pic.i_pts;
	if (isKeyframe)
		m_pic.i_type = X264_TYPE_IDR;
	else
		m_pic.i_type = X264_TYPE_AUTO;

	int i_frame_size = x264_encoder_encode(m_h, &_naluIter_t, &_naluIter, &m_pic, &_pic_out);

	if (i_frame_size > 0)
	{
		isKeyframe = (_pic_out.i_type == X264_TYPE_IDR);
		return 0;
	}
	return -1;
}

初始化 x264encoder, 发送rtp的关键在于每个关键帧的前面有sps pps, 实际上就是让

m_param.b_repeat_headers = 1;

不过默认值就是1 不用设置。


int X264Encoder::Initialize(int iWidth, int iHeight, int iRateBit, int iFps)
{
	x264_param_default_preset(&m_param, "ultrafast", "zerolatency");
	m_param.i_csp = X264_CSP_I420;
    m_param.i_width = iWidth;
    m_param.i_height = iHeight;

    m_param.i_fps_num = iFps;
    m_param.i_fps_den = 1;

    m_param.rc.i_bitrate = iRateBit;
    m_param.rc.i_rc_method = X264_RC_ABR;

    m_param.i_frame_reference = 2; /* 参考帧的最大帧数 */
    //m_param.i_keyint_max = 8;
    //m_param.i_keyint_min = 4;
    m_param.i_frame_total = 0;
    m_param.i_bframe = 0;
    m_param.i_threads = 1;
    m_param.rc.i_lookahead = 0;
    //m_param.i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO;
    m_param.i_sync_lookahead = 0;

    m_param.b_cabac = 1;
	m_param.analyse.b_transform_8x8 = 1;
	//m_param.b_repeat_headers = 1;
    m_param.i_level_idc = 12;
    //x264_param_apply_profile(&m_param, x264_profile_names[0]);
	m_param.i_log_level = X264_LOG_NONE;//X264_LOG_WARNING;// X264_LOG_ERROR;//X264_LOG_NONE;
	x264_param_apply_profile(&m_param, "baseline");
    /* 根据输入参数param初始化总结构 x264_t *h     */
    if( ( m_h = x264_encoder_open( &m_param ) ) == NULL )
    {
        //fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );

        return -1;
    }


    //x264_picture_alloc( &m_pic, X264_CSP_I420, m_param.i_width, m_param.i_height );

	x264_picture_init(&m_pic);
	memset(&m_pic, 0, sizeof(x264_picture_t));
	m_pic.i_type = X264_TYPE_AUTO;
    m_pic.i_qpplus1 = 0;
	m_pic.img.i_csp = X264_CSP_I420;
	m_pic.img.i_plane = 3;
    return 0;
}

ok,怎么发送比较效率高怎么改代码

ffmpeg 编码发送

对于ffmpeg来说,比较关键的就是 AV_CODEC_FLAG_GLOBAL_HEADER,这个值就是决定param中是否repeat header, 也就是:是否在关键帧前面加sps 和pps,如果是rtmp协议,我们加上,而rtp协议,我们不加。 这样在

_vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //全局参数

每个关键帧的前面都会加上sps和pps,这样使用vlc 这种工具写一个sdp文件,打开的时候碰到关键帧就可以解码出来。

时间戳

注意时间戳的基数是90000,为什么使用90000,因为这个数字让一些比较奇怪的帧数间隔时间也能成为整数。

发送事件间隔

这个太关键了,发送的时候一定要按照正式的帧率来发送,以下为示例代码
代码使用libx264 进行编码,当然使用openh254 , ffmpeg也是一样的,计算好时间间隔发送,如果为20帧,那就要每帧间隔50毫秒。

void VideoEncoderThread::Run()
{
	// 开始循环获取每一帧,并编码

	unsigned int timestamp = 0;
	unsigned int last_idr_timestamp = 0;

	bool is_first = true;
	//int x264buf_len = 1024 * 512;
	//unsigned char* x264buf = (unsigned char*)malloc(x264buf_len);
	int inter = 1000 / v_fps; // 50;
	while (false == IsStop())
	{
		//char* rgbbuf = ds_video_graph_->GetBuffer();
		unsigned int now_tick = ::GetTickCount();
		unsigned int next_tick = now_tick + inter;
		bool is_keyframe = false;
		timestamp = now_tick;
		if (timestamp - last_idr_timestamp >= 2000 || last_idr_timestamp ==0 )
		{
			is_keyframe = true;
			
			last_idr_timestamp = timestamp;
		}
		{
			std::unique_lock<std::mutex> lock(v_mt);
			x264_encoder_->Encode4RTP(v_yuvbuf, is_keyframe);
		}
		

		if (ok)
		{
			int num = x264_encoder_->GetNaluNumber();
			int size = 0;
			for (int i = 0; i < num; i++)
			{
				uint8_t *buf = x264_encoder_->GetNalu(i, size);
				sendrtp(buf, size, timestamp, is_keyframe);
			}
		}

		now_tick = ::GetTickCount();
		if (next_tick > now_tick)
		{
			Sleep(next_tick - now_tick);
		}
	}

	//free(yuvbuf);
	//free(x264buf);
	//free(encoder_rgbbuf);
   /* if (fp_264)
	{
		fclose(fp_264);
	}*/
}

摄像头问题

摄像头问题就很多了,web摄像头 也就是usb摄像头等什么时候拿到一帧是不确定的,就算是设定20帧,也未一秒钟必能拿到20帧,所以当中的缓存至关重要,如果不够,就要加帧,
1简单的做法 : 使用上一帧加帧
2 使用中间缓存,定时取帧,不要管上一帧下一帧是否相同,但是中间缓存要枷锁。

sdp 文件

v=0
m=video 6000 RTP/AVP 96
a=rtpmap:96 H264/90000
c=IN IP4 127.0.0.1

写好rtp 发送以后, 将以上文件存成test.sdp, 任何时候直接用vlc打开sdp文件 ,就可以看到图像,以上是在本机的6000端口 等待数据

界面显示

为了跨平台,用qt新做了一个发送界面,
在这里插入图片描述
使用vlc 接收
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/524568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第一章: Mybatis-Plus 之了解

目录 1.1&#xff1a;Mybatis-Plus介绍 1.2&#xff1a;代码及文档地址 1.3&#xff1a;特性 1.4&#xff1a;架构 1.5&#xff1a;作者 下面的图文来自于官方的介绍 1.1&#xff1a;Mybatis-Plus介绍 Mybatis-Plus 是一个 Mybatis 的增强工具&#xff0c;在Mybatis的基…

Seata之 Win系统和 Linux系统搭建

文章目录 1 Seata搭建1.1 Linux环境搭建1.1.1 准备工作1.1.2 下载1.1.3 建表1.1.4 配置 nacos1.1.4.1 新建命名空间1.1.4.2 上传配置至Nacos配置中心1.1.4.3 不上传而使用配置 1.1.5 修改 appplication.yml1.1.5.1 seata.store1.1.5.2 seata.config1.1.5.3 seata.registry 1.1.…

多模态:InstructBLIP

多模态&#xff1a;InstructBLIP IntroductionMethoddatasetInstruction-aware 视觉提取架构Dataset Balance 实验参考 Introduction 作者表示&#xff0c;与nlp任务不同&#xff0c;多模态任务由于引入额外的视觉输入&#xff0c;它的任务更加多样化&#xff0c;这似的联合多…

Immich让你从此告别百度网盘备份手机照片

一. Immich 是什么 Immich是一个开源的图片自托管服务&#xff0c;它能实现类似于百度网盘的照片自动备份、分类等功能&#xff0c;它同时提供了Web管理页面&#xff0c;和移动端APP&#xff0c;可以轻松备份手机中的照片至家庭服务器中。这一应用也在很多群辉玩家中用于替代“…

在 Windows 上安装 Helm包

一、前言 个人主页: ζ小菜鸡大家好我是ζ小菜鸡&#xff0c;让我们一起学习在 Windows 上安装 Helm包。如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连) 二、 Helm是什么 Helm是Kubernetes的包管理工具&#xff0c;类似于centos的yum&#xff0c;能够快速查找、下载和安装…

(2022 EMNLP)结合面部表情的情感分析

论文题目&#xff08;Title&#xff09;&#xff1a;Face-Sensitive Image-to-Emotional-Text Cross-modal Translation for Multimodal Aspect-based Sentiment Analysis 研究问题&#xff08;Question&#xff09;&#xff1a;面向面部敏感的图像-情感-文本翻译的跨模态的多…

【开源项目】TinyId 全网最好的分布式ID生成系统的源码解析

TINYID介绍 项目地址&#xff1a;https://github.com/didi/tinyid Tinyid是滴滴开发的一款分布式ID系统&#xff0c;Tinyid是在美团&#xff08;Leaf&#xff09;的leaf-segment算法基础上升级而来&#xff0c;不仅支持了数据库多主节点模式&#xff0c;还提供了tinyid-client客…

23种设计模式之适配器模式(Adapter Pattern)

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将23种设计模式中的适配器模式&#xff0c;此篇文章为一天学习一个设计模式系列文章&#xff0c;后面会分享其他模式知识。 如果文章有什么需要改进的地方还请大佬…

[GYCTF2020]EasyThinking

功能&#xff1a;登录&#xff0c;注册&#xff0c;搜索 回显登录用户名&#xff0c;搜索历史 简单测试搜索历史发现可能不存在sql注入 www.zip下载源码 访问一个不存在的路径&#xff0c;爆出 thinkphp的框架&#xff0c;版本是6.0.0 参考&#xff1a;ThinkPHP 6.0.1 漏洞…

MyBatis操作数据库实现增删改查

创建数据库 语句要分别执行 CREATE DATABASE mybatis;USE mybatis;CREATE TABLE user(id INT(10) NOT NULL PRIMARY KEY,name VARCHAR(20) DEFAULT NULL,INSERT INTO user(id,name,pwd) VALUES (1,张三,123456), (2,李四,121212), (3,王五,1314520) 搭配环境 1、在pojo包创…

25.基于混合整数规划方法的微网电池储能容量优化配置

关键词&#xff1a;储能容量优化 储能配置 微网 编程语言&#xff1a;matlab 主题&#xff1a;基于混合整数规划方法的微网电池储能容量优化配置 主要内容&#xff1a; 本代码目的为实现微电网内电池容量的优化配置&#xff0c;目标函数为配置过程中整体的运行成本最小或…

【Spring】Spring AOP面向切面编程

文章目录 什么是Spring AOP&#xff1f;为什么要使用AOP&#xff1f;AOP相关组成的概念切面切点通知连接点 Spring AOP实现创建切面创建切点创建通知创建连接点示例演示 Spring AOP的实现原理 什么是Spring AOP&#xff1f; 想要知道Spring AOP&#xff0c;就得先了解AOP AOP是…

【周期信号】工程测试-数据处理-信号分析课程试题:周期信号与周期信号相加,所得信号一定是周期信号吗?

一、问题分析 某课程的作业题中&#xff0c;有下面的一种题目&#xff0c;判断两个周期信号相加&#xff0c;是否是周期信号&#xff0c;以及计算周期长短是多少。 非常显然&#xff0c;1、3、4题都很容易判断。 第2题&#xff0c;我们重点分析。 二、网上的错误论述 在百…

Vivado运用 Language Template 来创建set_input_delay/set_output...

时序约束中的 set_input_delay/set_output_delay 约束一直是一个难点&#xff0c;无论是概念、约束值的计算&#xff0c;还是最终的路径分析&#xff0c;每一次都要费一番脑子。Vivado为方便用户创建输入输出接口的约束&#xff0c;整理出了一套非常实用的InputDelay/Output De…

【C++】类与对象(3)

【C】类与对象&#xff08;3&#xff09; 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2023.5.9 本篇博客干货比较多&#xff0c;主要是对类和对象知识的进一步加深&#xff0c;可能有点晦涩。主要介绍的内容为&#xff1a;深入构造函数&#xff0c;初始化列表&#xff0c…

《操作系统》——进程与线程

在上一期博客中&#xff0c;我们学习了关于操作系统中计算机系统概述的基本知识。今天&#xff0c;我将带领学习的是关于操作系统中一个非常重要的概念——进程与线程&#xff01;&#xff01;&#xff01; 目录 前言 &#xff08;一&#xff09;进程的基本概念和特征 1、进…

[golang gin框架] 33.Gin 商城项目- 集成支付宝微信支付、生成支付二维码、监听处理异步通知跳转到订单页面

一.界面展示 当用户点击去支付时,请求支付界面,并 展示对应订单相关数据,以及 支付方式相关操作,点击对应的支付方式,进行支付操作 该界面对应的功能: 1.进入该界面,后台逻辑判断: 是否存在该订单,如果不存在,则跳转到购物车页面;如果存在,则获取对应订单相关数据,并 渲染到页面…

0511课后作业(C高级)

1.编写一个名为myfirstshell.sh的脚本&#xff0c;它包括以下内容。 1、包含一段注释&#xff0c;列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOM…

iOS播放与编辑HDR视频

在iPhone12发布后&#xff0c;支持使用Dolby Vision来录制HDR视频。至此&#xff0c;升级到iOS14.1系统后&#xff0c;已经支持录制、播放、编辑和导出HDR视频。接下来&#xff0c;让我们一起探索HDR视频的各种操作。 一、HDR视频边编辑边预览 1、Profile与Level HDR视频中&…

Java奠基】实现面向对象编程方法

目录 标准的JavaBean类 设计对象并使用 对象封装 this关键字 构造方法 要知道对象是一个又一个能帮助我们解决问题的东西&#xff0c;但是这些东西并不是凭空出现的&#xff0c;需要我们根据设计图来进行制造&#xff0c;而这些一个一个的设计图就是一个一个的类。 标准的…