[Ubuntu]Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放——(二)(思路+代码解析)

        Scrcpy在上一篇博客中有所介绍,并且使用Scrcpy实现了手机屏幕yuv数据的提取([Ubuntu]Scrcpy获取手机屏幕yuv数据_又是谁在卷的博客-CSDN博客)。本文将介绍一个当下较为好用的消息中间件—Zeromq。通过Zeromq中间件对数据进行传输,我们最终通过opencv进行内存的数据读取,并实现连续播放的效果。

        往下阅读之前,记得看我的往期博客了解如何提取yuv数据呀([Ubuntu]Scrcpy获取手机屏幕yuv数据_又是谁在卷的博客-CSDN博客),这里就不再过多介绍yuv提取的知识了。接下里就开始实现Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放。

目录

1. Zeromq简单介绍,以及如何与Scrcpy项目源码进行对接(具体思路+代码解析)

1.1Zeromq简单介绍:Zeromq官网(ZeroMQ)

1.2.接下来让我们思考和Scrcpy对接时需要思考的的问题和流程框架。

 1.3.代码部分,针对以上结论进行实践

 1.3.1将yuv数据通过结构体进行封装

1.3.2将对应数据放入结构体

1.3.3在Scrcpy中创建Zeromq的PUB(发布者)


1. Zeromq简单介绍,以及如何与Scrcpy项目源码进行对接(具体思路+代码解析)

1.1Zeromq简单介绍:Zeromq官网(ZeroMQ

        简单来说,ZeroMQ嵌入式网络编程库的形式实现了一个并行开发框架。能够提供进程内(inproc)、进程间(IPC)、网络(TCP)和广播方式的消息信道,并支持扇出(fan-out)、发布-订阅(pub-sub)、任务分发(task distribution)、请求/响应(request-reply)等通信模式。与传统的消息中间件,Zeromq大大简化了消息传输的中间爱你过程,具有简介易操作的特点。(这里简单介绍,具体细节请参考官方文档。)

1.2.接下来让我们思考和Scrcpy对接时需要思考的的问题和流程框架。

        如果看过我的上一篇博客,我们知道yuv数据提取的过程是有顺序的。那我们就迎来了第一个需要思考的问题,

         1.我们如何将正确的顺序通过怎样的载体进行运输呢?

        这之中可能会有很多有趣的想法(比如yuv分开发送、yuv作为编码为字符串一起直接传输等等)。但是较好的方式是创建一个结构体作为yuv数据的载体,将y、u、v分别作为结构体单独的属性。通过结构体作为载体还有一个好处就是,我们每台设备的分辨率是不同的,分辨率在opencv的脚本中也需要用到(用于还原yuv数据),所以可以放在结构体里一起发送。

        载体选择完之后,yuv数据包装完毕之后,在发送之前。我们遇到了第二个问题。

        2.通过了解我们知道Zeromq有四个模型,我们需要选取最合适的模型。

        Zeromq中最常见的三种种基础模型

                1. REQ/REP 请求响应模型

                2. PUB/SUB发布订阅模型

                3. Pipeline pattern 管道模式

        我们要根据需求对模型进行选择。手机屏幕yuv数据的传输是从Scrcpy运行开始之后就源源不断的。也就是说,不管接收者是否受到数据,我们的发送端都不会停止发送。所以显而易见,在这里 2. 发布订阅者更合适。发布者(PUB)设置在Scrcpy的项目端,而订阅者(SUB)则设置在与opencv对接的python脚本中。

        选定模型之后,通过Zeromq的传输,在另一端和python脚本对接之后通过opencv呈现即可(后面会有代码解析)

 1.3.代码部分,针对以上结论进行实践

 1.3.1将yuv数据通过结构体进行封装

        因为yuv数据在scrcpy-master/app/src/decode.c文件中,所以我们将结构体创建在它的头文件中(decode.h)。代码如下图所示:

# 在decode.h添加如下代码
# 这里的576*1152是我手机分辨率除以1.875,这里算是压缩的操作
#define yuv_buf_size 576*1152
typedef struct{
    int cxt_width;
    int cxt_height;
    uint8_t data_y[yuv_buf_size];
    uint8_t data_u[yuv_buf_size/4];
    uint8_t data_v[yuv_buf_size/4];
}cxt_frame;

1.3.2将对应数据放入结构体

        以下代码和提取yuv数据时的操作如出一辙,也是在存有AVFrame的函数中(再次友情提醒:以下代码如果有疑惑,请参考我的上一篇博客)。我们通过memcpy函数将yuv数据分别拷贝到结构体对应的属性中。

# 创建结构体
cxt_frame yuv_frame;
# 定义长宽
int yuv_width = decoder->codec_ctx->width;
int yuv_height = decoder->codec_ctx->height;
yuv_frame.cxt_width = yuv_width;
yuv_frame.cxt_height = yuv_height;

# buf_size_aline用于对齐,以下存储yuv的操作和上一篇博客中提取yuv的操作如出一辙
int buf_size_aline = 0;
for(int i = 0;i<yuv_height;i++)
    {
        memcpy(yuv_frame.data_y + buf_size_aline,frame->data[0]+frame->linesize[0]*i,yuv_width);
        buf_size_aline += yuv_width;
    }

buf_size_aline = 0;
    
for(int i = 0;i<yuv_height/2;i++)
    {
        memcpy(yuv_frame.data_u + buf_size_aline,frame->data[1]+frame->linesize[1]*i,yuv_width/2);
        buf_size_aline += yuv_width/2;
    }

buf_size_aline = 0;
    
for(int i = 0;i<yuv_height/2;i++)
    {
        memcpy(yuv_frame.data_v + buf_size_aline,frame->data[2]+frame->linesize[2]*i,yuv_width/2);
        buf_size_aline += yuv_width/2;
    }
    
# 这里是通过Zeromq进行传输结构体数据的操作,这里暂时先不解释,到后面讲解zeromq时会回到此处进行解析
zmq_send(responder,&yuv_frame,sizeof(yuv_frame),ZMQ_DONTWAIT);

1.3.3在Scrcpy中创建Zeromq的PUB(发布者)

        我们在这之前需要清楚,Scrcpy是多线程的。发送消息的指令可以写在和yuv提取相同的位置。但是创建Zeromq发布者对象的时候不行,因为我们只要创建一次即可。写在函数中会反复创建(无法多次创建,会冲突)。所以我们必须找到这个线程进行初始化操作的地方创建Zeromq对象。在ubuntu中,我们可以在终端输入以下命令通过查找调用函数的位置,一步步向上层寻找。直到找到此线程的初始化位置,查找命令如下:

# 在此目录下的.c文件中查找名为“push_frame”的位置
$ find. -name "*.c" | xargs grep -n "push_frame"

 接下来在Zeromq中使用的函数可以在这篇博客里找到解析(ZeroMQ教程中文版_神马_逗_浮云的博客-CSDN博客_zeromq中文

经过查找,我们发现此线程的源头在名为stream.c的文件中,我们将在开始无条件for循环之前创建zeromq对象。代码和输入位置如下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Y-I5piv6LCB5Zyo5Y23,size_20,color_FFFFFF,t_70,g_se,x_16

#创建新的zeromq环境
void *context = zmq_ctx_new ();

# 这里有一个responder对象,我是将它初始化在stream.h的文件中了
# 选择ZMO_PUB发布订阅模型
responder = zmq_socket (context, ZMQ_PUB);

# 端口号,主机的随便一个可用的端口都行
int rc = zmq_bind (responder, "tcp://127.0.0.1:5565");

# 如果连接端口失败,则rc返回值为0
assert (rc == 0);

#最后别忘了在无限for循环之后关闭端口
zmq_close(responder);

 到这里再回去看在存储yuv数据那里的最后一行有发送yuv数据的代码就明白了。

至此我们发布者(PUB)端就设置完毕啦。成功完成Scrcpy和Zeromq的对接,剩下的就是创建python脚本(其他语言也行,我以python为例)接收yuv数据再使用opencv进行播放啦。

剩下内容请关注我的下一篇博客

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ZeroMQ是一个高性能、异步消息传输库,它提供了多种通信模式和协议,可以用于构建分布式系统和网络应用程序。而加密传输是指在数据传输过程中对数据进行加密,以保证数据的安全性和机密性。 在ZeroMQ中,可以通过使用加密算法和协议来实现数据的加密传输。一种常见的方式是使用Transport Layer Security (TLS)协议来进行加密传输。TLS是一种常用的安全协议,它可以在通信双方之间建立安全的连接,并对数据进行加密和身份验证。 要在ZeroMQ实现加密传输,可以按照以下步骤进行操作: 1. 生成证书和私钥:首先需要生成用于加密传输的证书和私钥。证书用于验证通信双方的身份,私钥用于对数据进行加密和解密。 2. 配置TLS上下文:在ZeroMQ中,可以使用OpenSSL库来配置TLS上下文。通过设置TLS上下文的参数,可以指定使用的加密算法、证书和私钥等信息。 3. 配置ZeroMQ套接字:在创建ZeroMQ套接字时,可以通过设置套接字的选项来启用TLS加密传输。可以指定使用的TLS上下文和验证模式等参数。 4. 进行加密传输:一旦配置完成,就可以使用ZeroMQ套接字进行加密传输了。数据传输过程中会被自动加密和解密,确保数据的安全性和机密性。 总结一下,ZeroMQ可以与TLS协议结合使用,通过配置TLS上下文和套接字选项来实现加密传输。这样可以保证数据传输过程中的安全性和机密性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又是谁在卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值