一套rk3588 rtsp服务器推流的 github 方案及记录 -01

这篇具有很好参考价值的文章主要介绍了一套rk3588 rtsp服务器推流的 github 方案及记录 -01。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我不生产代码,我只是代码的搬运工,相信我,看完这个文章你的图片一定能变成流媒体推出去。
诉求:使用opencv拉流,转成bgr数据,需要把处理后的数据(BGR)编码成264,然后推流推出去,相当于直播(实时编码)

播放器

超低延迟的RTSP播放器
https://github.com/tsingsee/EasyPlayer-RTSP-Win

青犀的一个播放器,直接下他的EasyPlayer-RTSP-Win用来测试就行。划重点,超低延时,我整体方案的延时大概是600-700ms,使用海康相机,rtsp拉流,做了yolo处理,再推出去,有编码,有解码,vlc的延时设置低了就回卡帧,Gop已经改成5了还是卡帧,没有测试Gop改成1的情况,但是vlc的延时和流畅,整体看是不太兼容的。ffmpeg使用nobuffer也会卡帧。直观感受卡的就是Gop的P帧。

服务器

live555 方案

如果你不着急的话。。。 可以试试这个方案,这方面的参考文献给列下面了,因为确实正经研究了几天还看了不少代码,认真想了应该怎么处理,但是确实不太想写,而且对我的需求来讲live555冗余了很多功能,再加上网上确实没有写好的,我又很着急要结果,确定方案能用,所以也没有用这个方案。

官方demo

live555自己的测试文件是有推流demo的,主要是根据实时需求推264文件,以及无脑做一个推264文件的服务器,当时看代码的时候一头雾水加上着急,也没太认真看,主要在live555\testProgs下面,testOnDemandRTSPServer,testH264VideoStreamer ,第二个是无脑推,第一个是你来一个请求,我从头开始给你播放一次视频文件。
这个东西的底层是向一个fTo指针里面拷贝264码流。
如果你Cpp、coding能力强的话,应该是能看懂直接改的,也就不用往后看了。

参考demo 零声 usb相机推流

网上基本上和我需求最接近的live555方案下的代码是国内的做音视频开发教学的一个零声出的视频还有他们传的这个代码。

主要功能是 v4l2相机读取mjpeg,然后ffmpeg的avcodec相关库编码,然后送live555,然后推实时流,像是改的testOnDemandRTSPServer,结构很清晰,除了不能用我也找不到原因外都挺好的。另外他的课是5K的,有点贵。

视频的话去B站带关键词,基本都能搜到,这个代码我加了那个联系QQ要到的。但是在我本地没有推成功,我也不确定是哪里的问题,编译过了,放在这里
https://gitee.com/qingfuliao/v4l2_ipc_live555?_from=gitee_search

在我这是下面这个demo 实现了一个相似的功能,编译实测是可以读取usb相机然后推流成功的。但是代码结构没有上面那个清晰。

参考demo

https://github.com/mpromonet/v4l2rtspserver

这个功能是基于linux的v4l2,使用264的方式读取相机视频流(如果你的usb相机不支持264输出,会驱动失败),然后直接拆帧把流发出去
需要自己下一个libv4l2cpp的代码放进来就能编译了

这个现在看稍微改一改就能用了,不过当时对整体没有概念,改了一阵子不知道怎么下手把我自己的码流变成demo的输入,码流送进去了但是没有推成功,定位了一会儿很难定位问题,也就搁置了。有兴趣的可以基于这个改一改。

https://blog.csdn.net/qq_43418269/article/details/122488866

这个方案我是成功了的,不过延时不太能满足我的需求,这个复现很快。他是用一个管道文件做的,我把编码之后264文件直接写到live555的testOnDemandRTSPServer.cpp这边的读取文件里面,然后逻辑是live555这边接收到请求,创建管道,相机程序初始化后阻塞住,管道被创建后往管道里写,然后另一边就开始播。。

这个就相当于是运行在一个demo里的两个程序。流倒是推出来了,只不过,我这样实现,延时很大,他说的百毫秒量级我做不到,我是2s左右。感觉也可能是我操作不当。

https://blog.csdn.net/lifexx/article/details/52823777

live555读文件改为内存读取实现,确实C++不太行,这个文章对我理解Live555,还有改成内存中的数据方向给了很大启发,但是没有按照他的做,而且他的参考代码无法运行。对我理解另一个推相机的demo有帮助

其他开源服务器框架

这个也是一个很容易就编译成功的服务器,可以使用这个做服务器,然后调用ffmpeg推流,在RK3588上也推成功了,基本没改make相关的配置,需要按照他给的快速开始流程使用git下附加库,功能很强大,但是对我的需求来讲,这个功能我进行二次开发比较慢。不排除我太菜。
https://github.com/ZLMediaKit/ZLMediaKit/tree/master

这里写这个的主要原因是他的一些文章对我的启发和快速上手有很大的参考意义,比如下面这个。

https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E6%80%8E%E4%B9%88%E6%B5%8B%E8%AF%95ZLMediaKit%E7%9A%84%E5%BB%B6%E6%97%B6%EF%BC%9F

RK3399 参考

网上有瑞芯微其他方案的rtsp推流,我只能帮忙排除错误选项
https://t.rock-chips.com/forum.php?mod=viewthread&tid=749&extra=page%3D1
如果你是在看这个帖子,可以不用看了,这个猫头的代码虽然推出去了,但是他的Rtsp是调库,这个库是闭源的,3588没有,这个网站注册要两三天才能通过,不必等这个,用不了。

rtsp推流

在github上搜索rtsp,排名最高的那个结果,就是那个小乌龟,

https://github.com/PHZ76/RtspServer
这个功能比较单一,但是足够满足我的需求了,他还使用他自己的库做了一个windows下的应用,windows上编译成功了,但是不太好用,不过对我理解他的Demo运行有一定帮助。因为用的是一套库。另外他主页还有一个rtmp ,我没进去看也没试能不能用。

https://github.com/PHZ76/DesktopSharing

一套rk3588 rtsp服务器推流的 github 方案及记录 -01,嵌入式,服务器,github,运维,linux,嵌入式硬件

下载安装

下载下来直接在3588上面make就可以,编译的是RtspServer-master/example里面的main 文件,这里的rtsp_h264_file.cpp是可以直接推运行推264文件的,一般不需要修改就能直接用,如果不能用,有可能是554端口被占用,改一个大点的就好了

    std::string suffix = "live";
	std::string ip = "127.0.0.1";
	std::string port = "5543";// 改这里 不要改那个"0.0.0.0" 那个是对的不用改
	std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;

然后rtsp_pusher.cpp还有rtsp_server.cpp都把发送文件的部分注释掉了,需要结合h264那个文件来对比把264码流写进去。

运行测试

编译出来之后运行 ./rtsp_h264_file ./test.264 就能推出来了
工程已经被我魔改过了,重新生成一个sample 来演示下结果
这是RK3588 服务器
一套rk3588 rtsp服务器推流的 github 方案及记录 -01,嵌入式,服务器,github,运维,linux,嵌入式硬件

这是VLC的界面IP
一套rk3588 rtsp服务器推流的 github 方案及记录 -01,嵌入式,服务器,github,运维,linux,嵌入式硬件

下面的是显示的结果
一套rk3588 rtsp服务器推流的 github 方案及记录 -01,嵌入式,服务器,github,运维,linux,嵌入式硬件

改cmake 支持opencv 、rknn,mpp

因为我使用的RKNN之间是在Qt里面编译的,工程使用的都是Cmake的cmakelists,他的makefile也不难改,主要的问题是我自己写的解码器,在使用makefile指定mpp库之后编译出来的mpp库运行不正常,具体报错找不到了,然后我qt上用是没问题的,定位到是makefile没写好,改成cmakelist就可以正常编译了
-g是为了支持gdb调试,配合我的vscode 调试配置文件,可以单步调试,全程在板上编译,没配置交叉编译环境

cmake_minimum_required(VERSION 3.5)
project(rtspserver)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSOCKLEN_T=socklen_t -g ")

find_package(OpenCV 4.5.5 REQUIRED)
find_package(OpenSSL REQUIRED)

# MPP
set(MPP_PATH /home/orangepi/code/mpp-develop/inc)
set(MPP_LIBS /home/orangepi/code/mpp-develop/mpp/librockchip_mpp.so)
include_directories(${MPP_PATH})

# OSAL
set(OSAL_PATH /home/orangepi/code/mpp-develop/osal/inc/ /home/orangepi/code/mpp-develop/utils)
set(OSAL_LIBS /home/orangepi/code/mpp-develop/osal/libosal.a /home/orangepi/code/mpp-develop/utils/libutils.a)
include_directories(${OSAL_PATH})

# RKNN lib
set(RKNN_API_PATH ${CMAKE_SOURCE_DIR}/lib)
set(RKNN_RT_LIB ${RKNN_API_PATH}/aarch64/librknnrt.so)
include_directories(${RKNN_API_PATH}/include)
include_directories(${CMAKE_SOURCE_DIR}/3rdparty)

# RGA
set(RGA_PATH ${CMAKE_SOURCE_DIR}/3rdparty/rga/RK3588)
set(RGA_LIB ${RGA_PATH}/lib/Linux/aarch64/librga.so)
include_directories(${RGA_PATH}/include)


aux_source_directory(src/xop SOURCE1)
aux_source_directory(src/net SOURCE2)

include_directories(    
    src    
    src/xop
    src/net
    src/3rdpart
    )

# add_executable(rtsp
# example/rtsp_server.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rtsp ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )
# add_executable(rh264
# example/rtsp_h264_file.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rh264 ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} OpenSSL::SSL OpenSSL::Crypto )
add_executable(sample
example/sample.cpp
${SOURCE1}
${SOURCE2}
src/3rdpart/md5/md5.hpp
)
target_link_libraries(sample ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS}  ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )

代码修改

代码是基于他的rtsp_server来修改的,主要修改的内容是sendFrameThread,大概思路是这样的,还差一个问题,怎么把你的原始mat图像转成264码流

bool IsKeyFrame(const char* data, uint32_t size)
{
	if (size > 4) {
		//0x67:sps ,0x65:IDR, 0x6: SEI
		if (data[4] == 0x67 || data[4] == 0x65 || 
			data[4] == 0x6 || data[4] == 0x27) {
			return true;
		}
	}

	return false;
}

void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients)
{       
	encoder e;
    
	
   
//  encoder相关 内存拷贝
	int size = 0;
	char* buffer ;

	// 编码标志位
    int i = 0;

    // 生成图像
    int width = 1920;
    int height = 1080;
	cv::Mat colorBar= cv::Mat::zeros(height, width, CV_8UC3);
    // 设置彩条的宽度
    int barWidth = width / 8; // 8个彩条,你可以根据需要调整
    // 生成彩条
    for (int i = 0; i < 8; ++i) {
        // 计算彩条的起始和结束位置
        int startX = i * barWidth;
        int endX = (i + 1) * barWidth;
        // 设置彩条颜色(BGR格式)
        cv::Vec3b color;
        if (i % 2 == 0) {
            color = cv::Vec3b(255, 0, 155); // 蓝色
        } else {
            color = cv::Vec3b(0, 255, 0); // 绿色
        }
        // 在colorBar上画出彩条
        colorBar(cv::Rect(startX, 0, barWidth, height)) = color;
    }

	while(1)
	{
		
		if(clients > 0) /* 会话有客户端在线, 发送音视频数据 */
		{
			{     
				xop::AVFrame videoFrame = {0};
				// printf("width is %d, height is %d",colorBar.rows,colorBar.cols);
				// 编码 发包
				if(0==i){
					// 第一帧有sps信息 给他两帧拼一起
					char *buffer1;
					int size1;
					e.init(buffer1,size1);
					videoFrame.size = size1;
					e.postAframe(colorBar,buffer,size);
					videoFrame.size += size;					
					videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
					memcpy(videoFrame.buffer.get(), buffer1, size1);
					memcpy(videoFrame.buffer.get()+size1, buffer, size);
					i++;
				}		
				else{
					e.postAframe(colorBar,buffer,size);
					videoFrame.size = size;  // 视频帧大小 
					videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
					memcpy(videoFrame.buffer.get(), buffer, videoFrame.size);
				}
				

				
				videoFrame.type = IsKeyFrame(buffer, size) ? xop::VIDEO_FRAME_I : xop::VIDEO_FRAME_P;
				// videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)

				videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
							
				// writeCharPointerToFile((char *)videoFrame.buffer.get(), videoFrame.size,  "filename.txt");		
				rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全
				/*
				//获取一帧 H264, 打包
				xop::AVFrame videoFrame = {0};
				videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)
				videoFrame.size = video frame size;  // 视频帧大小 
				videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
				videoFrame.buffer.reset(new uint8_t[videoFrame.size]);                    
				memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size);					
                   
				rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全
				*/
			}
                    
			{				
				/*
				//获取一帧 AAC, 打包
				xop::AVFrame audioFrame = {0};
				audioFrame.type = xop::AUDIO_FRAME;
				audioFrame.size = audio frame size;  /* 音频帧大小 
				audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳
				audioFrame.buffer.reset(new uint8_t[audioFrame.size]);                    
				memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size);

				rtsp_server->PushFrame(session_id, xop::channel_1, audioFrame); // 送到服务器进行转发, 接口线程安全
				*/
			}		
		}
		// xop::Timer::Sleep(20);  /* 实际使用需要根据帧率计算延时!  我这里处理延时很大,就不人工延迟了*/
	}
	videocapture->release();
	e.deinit((MPP_RET)0);
	yolo5.deinit();

}

rk3588编码

这方面网上的文章不太多,但是官方给了demo,都是中文,认真看看,功能都是能用的。
主要参考他的mpp-develop/test/mpi_enc_test 以及Rk3588-linux-v002\linux\docs\Linux\Multimedia\Rockchip_Developer_Guide_MPP_CN.pdf进行配置和使用。这相关的东西我之后再另开一个文章单独说,总之参考这部分可以做一个BGR888转成264存储的demo。
这里重点说一个概念,I、P、B帧
这个东西是264流编码的一个概念,正常你每一帧的图像都很大,比如一个1920*1080,每个像素点存一个BGR888的话,就是1920*1080*3 Byte =6220800 Byte ≈ 6M ,然后一秒30帧的话,一秒就要传180M,局域网或许勉强可以,但是对带宽压力也很大。所以这里就涉及到了压缩,264、265就是压缩标准,压缩中需要做两种压缩 帧内压缩帧间压缩

  • 帧内压缩:使用一定方法使用尽量小的空间存一帧数据。

  • 帧间压缩:利用帧和前后帧的关联来进一步的压缩视频。

这里我们重点关注帧间压缩。给一个参考文献
https://zhuanlan.zhihu.com/p/409527359
说的挺透彻的,这里我粗略说一下,看下面这个图
一套rk3588 rtsp服务器推流的 github 方案及记录 -01,嵌入式,服务器,github,运维,linux,嵌入式硬件

I帧 ,是帧间压缩里面的一帧完整图像,P帧是前向预测帧,B帧是双向预测帧
IDR帧是特殊的I帧,在编解码时候P、B帧可以参考I帧前面的帧进行复原,但是不能参考IDR帧前面的帧进行复原

而一个上面这样的循环,被编码成一组,我们指定了h264的gop大小,就确定了多少帧中有一个I帧
而我们在做直播,就导致为了低延时,不要B帧,gop 也要尽量的不要太大,如果要解码P帧,前面就一定要缓存I帧,

监测工具

wireshark, 这个感觉还是蛮必要的,至少你能看见客户端和服务器之间说没说话。如果你有耐心开RTSP 或者网络协议握手说明的话,你甚至能看到他们之间的握手流程。

杂记

中间遇到了一个问题,因为我这个地方没有公网,所以只能自己给开一个热点给电脑,PC和RK3588之间通过路由器连接,然后使用前面的某个demo的时候遇到的,主机向服务器(RK3588)发出视频请求时,服务器并没有直接给客户端发rtcp包,而是给一个200多的地址发包,而这个包在客户端收不到,但是他能收到rtp的协议包,所以vlc这边也不提示打不开,就是没有图像显示。
后来使用的方法是,和板子通过路由器网线连接,然后电脑PC wifi 连接路由器,然后路由器没有公网,再使用一个手机usb给电脑共享网络,让我的调试环境稳定可以接受到3588的流,和路由器网线连接的时候接受不到包,感觉是因为路由器没有网,使用网线连接时候被屏蔽了服务器功能,所以交给路由器的包转发请求没有被PC识别到,但是wifi连接的话,就算他没有网,也是不能忽略的。 目前是这样理解的。文章来源地址https://www.toymoban.com/news/detail-758489.html

到了这里,关于一套rk3588 rtsp服务器推流的 github 方案及记录 -01的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ZLMediaKit流媒体服务器 RTSP推流时候的堆栈

    先直接看图 这是ffmpeg向流媒体服务器推流时候的堆栈 引入C++ 11之后  堆栈会显得特别繁复冗余 看起来 也没有 以前没有C++11之前那样 简单明了   太复杂了 标记下  很多函数名字被我改了 因为原来的看起来 同名函数太多了 C++11 和lambada 匿名函数 让看堆栈 成了地狱模式 

    2023年04月20日
    浏览(57)
  • RTSP 和 RTMP通过ffmpeg实现将本地摄像头推流到RTSP服务器

    一、流媒体:RTSP 和RTMP 1、RTSP 和 RTMP的工作原理 1)RTSP工作原理 用户设备向视频流平台发送 RTSP 请求 视频流平台返回可以操作的请求列表,比如播放、暂停等 用户设备向视频流平台发送具体的请求,比如播放 视频流平台解析请求并调用指定机制启动视频流处理 由于 RTSP 依

    2024年02月05日
    浏览(54)
  • RTSP 和 RTMP原理 & 通过ffmpeg实现将本地摄像头推流到RTSP服务器

    0、参考资料 秒懂流媒体协议 RTMP 与 RTSP 什么是RTMP 和 RTSP?它们之间有什么区别? RTSP和RTMP的区别是什么? 1、RTSP 和 RTMP的工作原理 1)RTSP工作原理 用户设备向视频流平台发送 RTSP 请求 视频流平台返回可以操作的请求列表,比如 播放、暂停 等 用户设备向视频流平台发送具

    2024年02月08日
    浏览(65)
  • 海康威视摄像头RTSP使用nginx推流到服务器直播教程

    之前2020年在本科的时候,由于项目的需求需要将海康威视的摄像头使用推流服务器到网页进行直播。这里将自己半个月琢磨出来的步骤给大家发一些。切勿转载!!!! 使用网络摄像头中的rtsp协议---------通过rtsp链接让推流软件获取到视频流------推流软件推流到直播服务器

    2024年01月16日
    浏览(77)
  • RTSP向ZLM流媒体服务器的推流和拉流鉴权

    本篇博客的测试环境: Windows 10 + Qt 5.12.2 MSVC。 由于项目中使用了RTSP协议,为了防止别人知道我们的流地址随便就能播放观看我们的视频,所以就使用鉴权筛掉一些不合适的请求。 在鉴权之前呢,需要准备一下: ZLM流媒体服务器,是从ZLMediaKit中server中编译出来的,MediaServ

    2024年02月03日
    浏览(60)
  • Android 内置RTSP/RTMP服务器,实现局域网内视频推流与播放

    工作中有一个需求,在同一个局域网内, 需要将Android平板端(车机)上的摄像头上的画面,实时传输到手机上进行播放。 对于这个需求,我们想到了用 RTSP/RTMP 进行推流,然后在手机端拉流进行播放。 这个技术方案的主要技术点有 平板端内置 RTSP/RTMP 服务器 平板端获取摄像头

    2023年04月27日
    浏览(94)
  • RK3588实战:调用npu加速,yolov5识别图像、ffmpeg发送到rtmp服务器

    前言:最近在学习一些rk3588相关的东西,趁着这个项目,把学习的相关东西整合下,放到一个项目里面,巩固学习的知识。 项目名称:yolov5识别图像、ffmpeg发送到rtmp服务器 功能:1、opencv读取usb摄像头,使用RK3588自带的NPU推理yolov5s算法,识别图像            2、使用ffmpeg,

    2024年02月03日
    浏览(44)
  • Windows上搭建rtsp-simple-server流媒体服务器实现rtsp、rtmp等推流以及转流、前端html与Vue中播放hls(m3u8)视频流

    Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流: Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流_霸道流氓气质的博客-CSDN博客 上面讲了Nginx-http-flv-module+flv.js进行流媒体服务器搭建和前端播放视频流的过

    2024年02月01日
    浏览(59)
  • rk3588使用gstreamer推流

    在https://launchpad.net/上搜索软件名+ppa 找到需要的包后下面命令安装 如果不需要了下面命令删除 查看支持的编码器 不支持rkmpp的硬编码 下面安装插件gstreamer1.0-rockchip 这时已经支持硬件编码了 播放本地视频mp4 查找设备 播放视频画面 rk3588 硬件编码mpph264enc,使用gstreamer udp 传输

    2024年02月16日
    浏览(66)
  • Windows上搭建Nginx-http-flv实现rtsp视频流推流到rtmp流媒体服务器并转换和前端拉取http-flv视频流

    Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流: Nginx-http-flv-module流媒体服务器搭建+模拟推流+flv.js在前端html和Vue中播放HTTP-FLV视频流_霸道流氓气质的博客-CSDN博客 Windows上搭建Nginx RTMP服务器并使用FFmpeg实现本地视频推流: Vue中使用vue-vi

    2024年02月15日
    浏览(74)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包