scrcpy实现手机屏幕和ubuntu共享、推流、实时分割wifi环境下
有些时候我们需要将手机上的视频投到ubuntu上并进行处理,scrcpy就是一个非常低延时并且可以wifi共享的工具,本文主要针对其源码进行修改,实现ubuntu上实时分割手机画面,分为安装编译源(大坑)、修改源码、修改分割推理代码三部分。
scrcpy的使用和wifi连接可参考
一、安装编译源码
后面的源码修改有两个重要文件需要修改:stream.c和decoder.c,前者是用来把yuv流推到深度学习那边去的,后者是为了从scrcpy中把流推出来。如果你按照其他博客下载,即使跌跌撞撞编译成功,但发现没有这两个文件,太狗了,我这边找到最近的有这两个文件的是scrcpy1.22版本,千万别下错了!!!。需要下载的文件有两个:scrcpy源码和server
源码链接:https://github.com/Genymobile/scrcpy/tree/v1.22
server链接:Release scrcpy v1.22 · Genymobile/scrcpy · GitHub
下载完成后,解压scrcpy,善后meson build生成build文件夹,build-app里面把scrcpy-sever放进去,此时在build下运行ninja -Cbuild,此时如果会报错,如果报错消息是server没生成,此时去看看build-app里面有没有可执行文件,如果有那就编译结束了,./scrcpy运行即可
如果此时报错出现什么版本不一致或者其他错,进到/usr/local/share/scrcpy中把server往这里面拷贝一份。
至此,第一步编译运行源码完成。
二、修改源码
源码最重要的就是输出yuv流并通过本地端口广播出去,进入app/src下。修改decoder.c和stream.c以及对应的h文件,需要修改的部分如下:
decoder.c-----输出yuv流
-
-
-
-
-
-
-
-
-
-
-
-
######
-
-
-
static bool
-
push_frame_to_sinks(struct decoder *decoder, const AVFrame *frame) {
-
-
-
-
-
//声明结构体
-
myframe yuv_frame;
-
-
-
//初始化长宽
-
yuv_frame.width= decoder->codec_ctx->width;
-
yuv_frame.height=decoder->codec_ctx->height;
-
//读取数据
-
int offest=0;
-
for(int i=0;i<yuv_frame.height;i )
-
{
-
memcpy(yuv_frame.data_Y offest,frame->data[0] frame->linesize[0]*i,yuv_frame.width);
-
//指向下一行
-
offest = yuv_frame.width;
-
}
-
-
offest=0;
-
for(int i=0;i<yuv_frame.height/2;i )
-
{
-
memcpy(yuv_frame.data_U offest,frame->data[1] frame->linesize[1]*i,yuv_frame.width/2);
-
offest = yuv_frame.width/2;
-
}
-
-
offest=0;
-
for(int i=0;i<yuv_frame.height/2;i )
-
{
-
memcpy(yuv_frame.data_V offest,frame->data[2] frame->linesize[2]*i,yuv_frame.width/2);
-
offest = yuv_frame.width/2;
-
}
-
// printf("a");
-
-
int aa = zmq_send(response,&yuv_frame,sizeof(yuv_frame),ZMQ_DONTWAIT);
-
if (aa == -1) {
-
printf("zmq_send error: %s\n", zmq_strerror(errno));
-
}
-
-
-
// printf("%d",aa);
-
-
-
for (unsigned i = 0; i < decoder->sink_count; i) {
-
struct sc_frame_sink *sink = decoder->sinks[i];
-
if (!sink->ops->push(sink, frame)) {
-
LOGE("Could not send frame to sink %d", i);
-
return false;
-
}
-
}
-
-
-
-
return true;
-
}
decoder.h-------声明结构体和scoket全局变量
-
-
-
typedef struct{
-
int width;
-
int height;
-
uint8_t data_Y[yuv_size];
-
uint8_t data_U[yuv_size/4];
-
uint8_t data_V[yuv_size/4];
-
}myframe;
-
-
extern void *response;
stream.c----初始化socket端口,for循环前初始,最终end的时候删除
-
###先声明变量
-
void *response = NULL;
-
###
-
-
-
-
-
-
response = zmq_socket (context, ZMQ_PUB);
-
-
int rc = zmq_bind(response, "tcp://127.0.0.1:5555");
-
// printf("%d",rc);
-
// printf("111");
-
assert (rc == 0);
-
-
for (;;) {
-
-
bool ok = stream_recv_packet(stream, packet);
-
-
if (!ok) {
-
// end of stream
-
break;
-
}
-
-
ok = stream_push_packet(stream, packet);
-
-
av_packet_unref(packet);
-
if (!ok) {
-
// cannot process packet (error already logged)
-
break;
-
-
-
}
-
-
-
}
-
-
LOGD("End of frames");
-
-
if (stream->pending) {
-
av_packet_free(&stream->pending);
-
}
-
-
av_packet_free(&packet);
-
finally_close_parser:
-
av_parser_close(stream->parser);
-
finally_close_sinks:
-
stream_close_sinks(stream);
-
finally_free_codec_ctx:
-
avcodec_free_context(&stream->codec_ctx);
-
end:
-
if (response) {
-
zmq_close(response);
-
}
-
if (context) {
-
zmq_ctx_term(context);
-
}
-
stream->cbs->on_eos(stream, stream->cbs_userdata);
-
-
return 0;
-
}
至此,源码修改完成,yuv流输出到本地端口,下一步让我们用起来吧!!!
三、订阅与深度学习实时分割
我先给一份实例直接订阅imshow的,如果需要融合到其他深度学习比如检测分割之类的程序基于此进行修改即可
-
import zmq
-
import numpy as np
-
import cv2
-
-
# 创建一个ZeroMQ Context
-
context = zmq.Context()
-
-
# 创建一个套接字并连接
-
socket = context.socket(zmq.SUB)
-
socket.connect("tcp://127.0.0.1:5555")
-
socket.setsockopt_string(zmq.SUBSCRIBE, '')
-
-
width = 1024# 这里设置你的宽度
-
height = 448# 这里设置你的高度
-
-
while True:
-
# 从套接字接收myframe结构体
-
yuv_frame = socket.recv()
-
-
# 将bytes数据转化为numpy数组
-
y_data = np.frombuffer(yuv_frame[8:8 width*height], dtype=np.uint8).reshape(height, width)
-
u_data = np.frombuffer(yuv_frame[8 width*height:8 width*height*5//4], dtype=np.uint8).reshape(height//2, width//2)
-
v_data = np.frombuffer(yuv_frame[8 width*height*5//4:8 width*height*3//2], dtype=np.uint8).reshape(height//2, width//2)
-
-
# 这里你可以将YUV格式的图像转化为RGB或者其他你需要的格式,然后进行显示或者处理
-
# 例如,使用OpenCV库的cvtColor函数转化为BGR格式
-
yuv_image = cv2.merge([y_data, cv2.resize(u_data, (width, height)), cv2.resize(v_data, (width, height))]).astype(np.uint8)
-
bgr_image = cv2.cvtColor(yuv_image, cv2.COLOR_YUV2BGR)
-
cv2.imwrite("./1.jpg",bgr_image)
-
# 实时显示视频
-
cv2.imshow('Video', bgr_image)
-
-
# 等待1毫秒,如果此时按下“q”键,那么退出循环
-
if cv2.waitKey(1) & 0xFF == ord('q'):
-
break
-
-
# 销毁所有窗口
-
cv2.destroyAllWindows()
然后给一份完用unet做分割的代码
-
elif mode == "video":
-
# 创建一个ZeroMQ Context
-
context = zmq.Context()
-
-
# 创建一个套接字并连接
-
socket = context.socket(zmq.SUB)
-
socket.connect("tcp://127.0.0.1:5555")
-
socket.setsockopt_string(zmq.SUBSCRIBE, '')
-
-
width = 1024 # 这里设置你的宽度
-
height = 448 # 这里设置你的高度
-
-
-
-
frame_counter = 0
-
fps = 0.0
-
while True:
-
t1 = time.time()
-
# 从套接字接收myframe结构体
-
yuv_frame = socket.recv()
-
frame_counter = 1
-
if frame_counter % 10 != 0: # Only process every 10th frame
-
continue
-
-
# 将bytes数据转化为numpy数组
-
y_data = np.frombuffer(yuv_frame[8:8 width*height], dtype=np.uint8).reshape(height, width)
-
u_data = np.frombuffer(yuv_frame[8 width*height:8 width*height*5//4], dtype=np.uint8).reshape(height//2, width//2)
-
v_data = np.frombuffer(yuv_frame[8 width*height*5//4:8 width*height*3//2], dtype=np.uint8).reshape(height//2, width//2)
-
-
yuv_image = cv2.merge([y_data, cv2.resize(u_data, (width, height)), cv2.resize(v_data, (width, height))]).astype(np.uint8)
-
frame = cv2.cvtColor(yuv_image, cv2.COLOR_YUV2BGR)
-
frame1 = frame
-
-
frame = Image.fromarray(np.uint8(frame))
-
# # 进行检测
-
# t2 = time.time()
-
# print(t2-t1)
-
-
frame = np.array(unet.detect_image(frame))
-
-
cv2.imshow("video", frame)
-
# 等待1毫秒,如果此时按下“q”键,那么退出循环
-
if cv2.waitKey(1) & 0xFF == ord('q'):
-
break
-
t2 = time.time()
-
print(t2-t1)
-
-
-
print("Video Detection Done!")
-
-
-
-
cv2.destroyAllWindows()
记得一定要搁几帧读一下socket,不然推理无法实时,速度太慢,到时候socket里面堵塞太多东西了会巨卡------这里卡太久了,一步步debug才发现的
这里跑的是voc数据集的unet分割,可见才0.3s的延时,凑合凑合就够用了!!!
error1:
sdl2-config found: NO need '>= 2.0.5'
Run-time dependency sdl2 found: NO (tried pkgconfig and config-tool)
app/meson.build:94:4: ERROR: Dependency "sdl2" not found, tried pkgconfig and config-tool
solution:sudo apt-get install libsdl2-dev
error2:ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
solution:sudo apt-get install openjdk-8-jdk
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgaccfc
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13