pb利用NetMessageBufferSend在局域网发送中文消息(实现cmd中 NET SEND功能)

本文介绍了一个用于网络消息发送的工具,其版本已更新以支持发送中文。使用时需确保Messenger服务已启用,并提供了包括创建文件、发送消息等功能的详细说明。
 

         这是一个窗口w_main的导出对象,需要的自己保存为文件,再导入。

        这个版本其实来自网上,只是网上的那个不能发送中文,现在做了修改,支持发送中文了。

        记住,net send 依赖于系统服务Messenger,在使用API函数 NetMessageBufferSend 前必须保证该服务已经启用(需要在程序中自动启用该服务的,可以下载pb操作系统服务——重启MSSQLSERVER 自己整合)。

 

$PBExportHeader$w_main.srw
forward
global type w_main from window
end type
type mle_1 from multilineedit within w_main
end type
type cb_1 from commandbutton within w_main
end type
type sle_1 from singlelineedit within w_main
end type
type st_2 from statictext within w_main
end type
type st_1 from statictext within w_main
end type
type icmp_echo_reply from structure within w_main
end type
end forward

type icmp_echo_reply from structure
    unsignedlong        address
    unsignedlong        status
    unsignedlong        roundtriptime
    unsignedlong        datasize
    unsignedlong        reserved[3]
    character       data[250]
end type

global type w_main from window
integer x = 1056
integer y = 484
integer width = 1531
integer height = 1152
boolean titlebar = true
string title = "NETMESSAGESEND"
boolean controlmenu = true
boolean minbox = true
boolean resizable = true
long backcolor = 80269524
mle_1 mle_1
cb_1 cb_1
sle_1 sle_1
st_2 st_2
st_1 st_1
end type
global w_main w_main

type prototypes
Function ulong IcmpCreateFile () Library "icmp.dll"
Function long IcmpSendEcho (ulong IcmpHandle, ulong DestinationAddress, string RequestData,long RequestSize, long RequestOptions, Ref icmp_echo_reply ReplyBuffer, long ReplySize, long Timeout ) Library "icmp.dll" Alias for "IcmpSendEcho"
Function long IcmpCloseHandle (ulong IcmpHandle) Library "icmp.dll"
Function ulong inet_addr (string cp) Library "ws2_32.dll" Alias for "inet_addr"

Function ulong NetMessageBufferSend(ulong servername, ref char msgname[],ulong fromname, ref char buf[], ulong buflen) Library "netapi32.dll" Alias for "NetMessageBufferSend"
function ulong MultiByteToWideChar(uint codepage, ulong dwflags, ref string lpmultibytestr, int cchmultibyte, ref char lpwidecharstr[], int cchwidechar) library "kernel32.dll" alias for "MultiByteToWideChar"

end prototypes
type variables
CONSTANT ulong NERR_Success = 0

end variables
forward prototypes
public function boolean wf_netmessagebuffersend (string as_sendto, string as_msgtext)
public function boolean wf_ping (string as_ipaddress, string as_echomsg)
public subroutine wf_string2unicode (ref character as_unicode[], string as_string)
end prototypes

public function boolean wf_netmessagebuffersend (string as_sendto, string as_msgtext);Ulong lul_result, lul_buflen

Char lc_msgname[],lc_msgtext[]
string ls1, ls2
wf_string2unicode( lc_msgname, as_sendto)
wf_string2unicode( lc_msgtext, as_msgtext)

lul_buflen = UpperBound(lc_msgtext)

lul_result = NetMessageBufferSend(0, lc_msgname,0, lc_msgtext, lul_buflen)

If lul_result = NERR_Success Then
    Return True
Else
    Return False
End If

end function

public function boolean wf_ping (string as_ipaddress, string as_echomsg);ULong lul_address, lul_handle
Long ll_rc, ll_size
String ls_reply
icmp_echo_reply lstr_reply

lul_address = inet_addr(as_ipaddress)
If lul_address > 0 Then
    lul_handle = IcmpCreateFile()
    ll_size = Len(as_echomsg)
    ll_rc = IcmpSendEcho(lul_handle, lul_address, &
                        as_echomsg, ll_size, 0, &
                        lstr_reply, 278, 200)
    IcmpCloseHandle(lul_handle)
    If ll_rc <> 0 Then
        If lstr_reply.Status = 0 Then
            ls_reply = String(lstr_reply.Data)
            If ls_reply = as_echomsg Then
                Return True
            End If
        End If
    End If
End If
 
Return False

end function

public subroutine wf_string2unicode (ref character as_unicode[], string as_string);char lc_data[]
long ll_len, ll_rc
ll_len = lenw(as_string) * 2
lc_data = space(ll_len)

ll_rc = multibytetowidechar(936, 0, as_string , -1, lc_data, ll_len)

as_unicode = lc_data
as_unicode[upperbound(as_unicode) + 1] = char(0)
as_unicode[upperbound(as_unicode) + 1] = char(0)
end subroutine

on w_main.create
this.mle_1=create mle_1
this.cb_1=create cb_1
this.sle_1=create sle_1
this.st_2=create st_2
this.st_1=create st_1
this.Control[]={this.mle_1,&
this.cb_1,&
this.sle_1,&
this.st_2,&
this.st_1}
end on

on w_main.destroy
destroy(this.mle_1)
destroy(this.cb_1)
destroy(this.sle_1)
destroy(this.st_2)
destroy(this.st_1)
end on

type mle_1 from multilineedit within w_main
integer x = 27
integer y = 264
integer width = 1399
integer height = 604
integer taborder = 20
integer textsize = -10
integer weight = 400
fontcharset fontcharset = gb2312charset!
fontpitch fontpitch = variable!
string facename = "方正姚体"
long textcolor = 33554432
string text = "你好"
borderstyle borderstyle = stylelowered!
end type

type cb_1 from commandbutton within w_main
integer x = 1070
integer y = 904
integer width = 357
integer height = 108
integer taborder = 30
integer textsize = -10
integer weight = 400
fontcharset fontcharset = gb2312charset!
fontpitch fontpitch = variable!
string facename = "方正姚体"
string text = " 发送(&S)"
end type

event clicked;if not wf_ping(trim(sle_1.text),"") then
    messagebox("提示","指定目标地址不存在或不通!")
    return
end if

 

if wf_NetMessageBufferSend(trim(sle_1.text),trim(mle_1.text)) then
   //messagebox("提示","发送成功!")
else
   messagebox("提示","发送失败!")   
end if

end event

type sle_1 from singlelineedit within w_main
integer x = 430
integer y = 48
integer width = 997
integer height = 92
integer taborder = 10
integer textsize = -10
integer weight = 400
fontcharset fontcharset = gb2312charset!
fontpitch fontpitch = variable!
string facename = "方正姚体"
long textcolor = 33554432
string text = "hhyy"
boolean autohscroll = false
borderstyle borderstyle = stylelowered!
end type

type st_2 from statictext within w_main
integer x = 14
integer y = 172
integer width = 379
integer height = 76
integer textsize = -10
integer weight = 400
fontcharset fontcharset = gb2312charset!
fontpitch fontpitch = variable!
string facename = "方正姚体"
long textcolor = 33554432
long backcolor = 67108864
boolean enabled = false
string text = "发送内容:"
boolean focusrectangle = false
end type

type st_1 from statictext within w_main
integer x = 14
integer y = 52
integer width = 379
integer height = 76
integer textsize = -10
integer weight = 400
fontcharset fontcharset = gb2312charset!
fontpitch fontpitch = variable!
string facename = "方正姚体"
long textcolor = 33554432
long backcolor = 67108864
boolean enabled = false
string text = "目标地址:"
boolean focusrectangle = false
end type


 

本课题旨在设计并实现一套以STM32微控制器为核心的智慧农业灌溉系统。该系统集成土壤湿度、温湿度、光照强度等多种传感器与水泵、电磁阀等执行器,通过实时数据采集与智能决策,实现对农田环境的精准监测、按需灌溉与远程控制,具备低成本、高可靠性与易部署的特点。主要研究内容如下:1.系统总体方案设计: 深入分析智慧农业灌溉系统的功能需求,重点围绕节水效率、控制精度与远程监控能力进行技术可行性论证。设计系统的整体架构,包括硬件架构(主控芯片选型、传感器与执行器配置、电源与通信模块设计)和软件架构(主控制流程、数据处理逻辑、通信协议与用户交互界面) 2.系统硬件电路设计与实现 (1)主控核心电路设计:以STM32F103C8T6微控制器为核心,设计包括电源管理、时钟、复位、调试接口在内的最小系统电路。 (2)传感器采集电路设计:设计土壤湿度传感器、温湿度传感器(如DHT11)、光照传感器等与STM32的接口电路,确保信号稳定与抗干扰能力。 (3)执行器驱动电路设计:设计继电器驱动电路,用于控制水泵、电磁阀等灌溉执行机构,确保驱动能力与电气安全。 (4)通信模块电路设计:集成Wi-Fi模块(如ESP8266)或4G模块,实现STM32与云平台或移动终端的数据交互,设计相应的串口或SPI通信接口电路。 3. 系统软件程序设计与实现: (1)开发环境搭建:基于Keil MDK或STM32CubeIDE搭建软件开发环境,配置HAL库或标准库,完成基本外设初始化。 (2)传感器数据采集与处理:编写传感器驱动代码,实现土壤湿度、温湿度等数据的实时采集,并通过滤波算法与阈值判断提高数据可靠性。 (3) 灌溉控制逻辑实现: 自动灌溉功能:根据土壤湿度阈值自动启停灌溉设备; 环境监控功能实现土壤湿度、水箱剩余水量等传感器的实时数据采集、阈值判断及相应的联动控制逻辑(洒水、启动风扇)。 报警功能实现本地声光报警(蜂鸣器)与远程短信报警的联动机制。 通信协议与远程控制实现:编写程序实现STM32与GSM模块的AT指令交互,完成报警短信的发送实现与手机APP(可通过云服务器或局域网)的数据交互协议,完成状态上报和远程控制指令的解析与执行。
最新发布
10-21
<think>我们想要将YOLO目标检测的结果(即绘制了检测框的帧)通过FFmpeg推流出去。整体流程如下: 1. 使用OpenCV读取摄像头或视频源。 2. 对每一帧进行YOLO目标检测(假设已经有一个YOLO检测函数)。 3. 将检测结果(绘制了框、标签等的图像)通过FFmpeg推流到RTMP服务器。 我们之前已经实现了使用FFmpeg推流的框架,现在需要将YOLO检测集成进去。 步骤: 1. 初始化摄像头(或视频源)和FFmpeg推流上下文。 2. 循环读取帧,对每一帧进行YOLO检测。 3. 将检测后的帧(OpenCV的Mat,格式为BGR)转换为YUV420P(因为H264编码通常使用此格式)。 4. 编码并推流。 注意:YOLO检测部分需要有一个模型加载和推理的过程,这里假设我们已经有一个YOLO类(例如YOLOv5)可以完成检测。 我们将使用以下引用的一些思路: 引用[2]提到了使用OpenCV+FFmpeg推流,并且在检测部分使用了YOLOv5。我们可以参考其流程。 具体实现: 1. 初始化部分: - 初始化OpenCV的VideoCapture。 - 初始化FFmpeg的输出上下文(AVFormatContext),编码器(H264)等。 - 初始化SwsContext用于颜色空间转换(BGR24 to YUV420P)。 2. 在循环: - 读取一帧。 - 使用YOLO模型进行检测(并绘制结果)。 - 将绘制后的BGR图像转换为YUV420P。 - 编码并发送。 3. 清理资源。 我们将假设YOLO检测函数已经存在,其函数签名可能为: void detect_and_draw(cv::Mat& frame); 或者,我们可以使用一个类来封装YOLO模型,如: class YOLODetector { public: YOLODetector(const std::string& model_path); void detect(cv::Mat& frame); }; 下面我们编写代码,注意错误处理和资源释放。 注意:由于推流对实时性要求较高,我们需要确保YOLO检测的速度足够快,否则可能需要降低分辨率或使用更轻量的模型。 代码结构: 我们将在主函数完成所有步骤。为了简洁,省略了部分错误检查,实际应用应添加。 参考代码:</think># C++实现YOLO检测结果通过FFmpeg推流 下面是一个完整的C++实现方案,将YOLO目标检测结果通过FFmpeg进行RTMP推流。该方案结合了OpenCV、FFmpeg和YOLO目标检测模型。 ## 完整实现代码 ```cpp #include <opencv2/opencv.hpp> #include <opencv2/dnn.hpp> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <libavutil/opt.h> } // YOLO检测函数 void detect_objects(cv::Mat& frame, cv::dnn::Net& net, const std::vector<std::string>& classes) { // 预处理 cv::Mat blob; cv::dnn::blobFromImage(frame, blob, 1/255.0, cv::Size(416, 416), cv::Scalar(0,0,0), true, false); // 设置网络输入 net.setInput(blob); // 前向传播 std::vector<cv::Mat> outputs; net.forward(outputs, net.getUnconnectedOutLayersNames()); // 后处理 - 解析检测结果 std::vector<int> classIds; std::vector<float> confidences; std::vector<cv::Rect> boxes; float confThreshold = 0.5; float nmsThreshold = 0.4; for (auto& output : outputs) { auto* data = (float*)output.data; for (int i = 0; i < output.rows; i++, data += output.cols) { cv::Mat scores = output.row(i).colRange(5, output.cols); cv::Point classIdPoint; double confidence; cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint); if (confidence > confThreshold) { int centerX = (int)(data[0] * frame.cols); int centerY = (int)(data[1] * frame.rows); int width = (int)(data[2] * frame.cols); int height = (int)(data[3] * frame.rows); int left = centerX - width / 2; int top = centerY - height / 2; classIds.push_back(classIdPoint.x); confidences.push_back((float)confidence); boxes.push_back(cv::Rect(left, top, width, height)); } } } // 应用非极大值抑制 std::vector<int> indices; cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices); // 绘制检测结果 for (size_t i = 0; i < indices.size(); i++) { int idx = indices[i]; cv::Rect box = boxes[idx]; std::string label = cv::format("%s: %.2f", classes[classIds[idx]].c_str(), confidences[idx]); cv::rectangle(frame, box, cv::Scalar(0, 0, 255), 2); cv::putText(frame, label, cv::Point(box.x, box.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1); } } int main() { // 1. 初始化摄像头 cv::VideoCapture cap(0); if (!cap.isOpened()) { std::cerr << "无法打开摄像头" << std::endl; return -1; } // 设置分辨率 int width = 640, height = 480; cap.set(cv::CAP_PROP_FRAME_WIDTH, width); cap.set(cv::CAP_PROP_FRAME_HEIGHT, height); // 2. 加载YOLO模型 cv::dnn::Net net = cv::dnn::readNetFromDarknet("yolov3.cfg", "yolov3.weights"); if (net.empty()) { std::cerr << "无法加载YOLO模型" << std::endl; return -1; } net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU); // 加载类别名称 std::vector<std::string> classes; std::ifstream classFile("coco.names"); if (classFile.is_open()) { std::string className; while (std::getline(classFile, className)) { classes.push_back(className); } } // 3. 初始化FFmpeg输出上下文 avformat_network_init(); AVFormatContext* fmt_ctx = nullptr; const char* output_url = "rtmp://your-server/live/streamkey"; // 分配输出上下文 if (avformat_alloc_output_context2(&fmt_ctx, nullptr, "flv", output_url) < 0) { std::cerr << "无法创建输出上下文" << std::endl; return -1; } // 4. 创建视频流并配置编码器 AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { std::cerr << "找不到H264编码器" << std::endl; return -1; } AVStream* stream = avformat_new_stream(fmt_ctx, codec); if (!stream) { std::cerr << "无法创建输出流" << std::endl; return -1; } AVCodecContext* codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { std::cerr << "无法分配编码器上下文" << std::endl; return -1; } // 配置编码器参数 codec_ctx->width = width; codec_ctx->height = height; codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; codec_ctx->time_base = (AVRational){1, 25}; // 25fps codec_ctx->bit_rate = 800000; // 800kbps codec_ctx->gop_size = 10; // 关键帧间隔 // 设置低延迟参数 av_opt_set(codec_ctx->priv_data, "preset", "ultrafast", 0); av_opt_set(codec_ctx->priv_data, "tune", "zerolatency", 0); // 打开编码器 if (avcodec_open2(codec_ctx, codec, nullptr) < 0) { std::cerr << "无法打开编码器" << std::endl; return -1; } // 将编码器参数复制到流 if (avcodec_parameters_from_context(stream->codecpar, codec_ctx) < 0) { std::cerr << "无法复制编码器参数" << std::endl; return -1; } // 5. 打开网络输出流 if (!(fmt_ctx->oformat->flags & AVFMT_NOFILE)) { if (avio_open(&fmt_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0) { std::cerr << "无法打开输出流: " << output_url << std::endl; return -1; } } // 写入头部信息 if (avformat_write_header(fmt_ctx, nullptr) < 0) { std::cerr << "无法写入流头部" << std::endl; return -1; } // 6. 初始化颜色转换器 (BGR24→YUV420P) SwsContext* sws_ctx = sws_getContext( width, height, AV_PIX_FMT_BGR24, width, height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, nullptr, nullptr, nullptr ); if (!sws_ctx) { std::cerr << "无法创建SWS上下文" << std::endl; return -1; } // 7. 初始化帧和包 AVFrame* frame = av_frame_alloc(); if (!frame) { std::cerr << "无法分配视频帧" << std::endl; return -1; } frame->format = AV_PIX_FMT_YUV420P; frame->width = width; frame->height = height; if (av_frame_get_buffer(frame, 0) < 0) { std::cerr << "无法分配帧缓冲区" << std::endl; return -1; } AVPacket pkt; av_init_packet(&pkt); pkt.data = nullptr; pkt.size = 0; // 8. 推流主循环 cv::Mat bgr_frame; int64_t frame_count = 0; while (cap.read(bgr_frame)) { // 执行YOLO目标检测并绘制结果 detect_objects(bgr_frame, net, classes); // 转换OpenCV BGR帧到YUV uint8_t* src_data[1] = { bgr_frame.data }; int src_linesize[1] = { static_cast<int>(bgr_frame.step) }; sws_scale(sws_ctx, src_data, src_linesize, 0, height, frame->data, frame->linesize); // 设置时间戳 frame->pts = frame_count; frame_count++; // 编码帧 int ret = avcodec_send_frame(codec_ctx, frame); if (ret < 0) { std::cerr << "发送帧到编码器失败" << std::endl; continue; } // 获取编码后的包 while (ret >= 0) { ret = avcodec_receive_packet(codec_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { std::cerr << "编码期间出错" << std::endl; break; } // 设置包的时间戳 pkt.stream_index = stream->index; av_packet_rescale_ts(&pkt, codec_ctx->time_base, stream->time_base); // 写入包 if (av_interleaved_write_frame(fmt_ctx, &pkt) < 0) { std::cerr << "写入帧失败" << std::endl; } av_packet_unref(&pkt); } } // 9. 资源释放 av_write_trailer(fmt_ctx); if (sws_ctx) sws_freeContext(sws_ctx); if (frame) av_frame_free(&frame); if (codec_ctx) avcodec_free_context(&codec_ctx); if (fmt_ctx && !(fmt_ctx->oformat->flags & AVFMT_NOFILE)) { avio_closep(&fmt_ctx->pb); } if (fmt_ctx) avformat_free_context(fmt_ctx); cap.release(); return 0; } ``` ## 关键实现说明 ### 1. YOLO目标检测集成 - 使用OpenCV的dnn模块加载YOLO模型 - `detect_objects`函数处理检测和结果绘制: - 预处理输入图像 - 执行前向传播 - 应用非极大值抑制(NMS) - 绘制边界框和标签 ### 2. FFmpeg推流优化 - **低延迟配置**: ```cpp av_opt_set(codec_ctx->priv_data, "preset", "ultrafast", 0); av_opt_set(codec_ctx->priv_data, "tune", "zerolatency", 0); ``` - **关键帧间隔**: ```cpp codec_ctx->gop_size = 10; // 每10帧一个关键帧 ``` - **时间戳处理**: ```cpp frame->pts = frame_count; // 设置帧时间戳 av_packet_rescale_ts(&pkt, codec_ctx->time_base, stream->time_base); ``` ### 3. 资源管理 - 使用RAII原则管理资源: - `av_frame_free`释放帧 - `avcodec_free_context`释放编码器上下文 - `avformat_free_context`释放格式上下文 - 错误检查所有关键操作 ## 性能优化建议 1. **硬件加速**: ```cpp // NVIDIA GPU加速 net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); // FFmpeg硬件编码 AVCodec* codec = avcodec_find_encoder_by_name("h264_nvenc"); ``` 2. **多线程处理**: ```cpp // OpenCV多线程 cv::setNumThreads(4); // FFmpeg多线程编码 codec_ctx->thread_count = 4; codec_ctx->thread_type = FF_THREAD_FRAME; ``` 3. **动态分辨率调整**: ```cpp // 根据网络状况调整分辨率 if (network_latency > threshold) { width = 480; height = 360; // 重新初始化编码器和转换器 } ``` ## 常见问题解决 1. **连接失败**: - 检查RTMP地址格式:`rtmp://ip:port/app/stream_key` - 确保服务器端口(默认1935)开放 2. **检测延迟过高**: - 使用更小的YOLO模型(如YOLOv3-tiny) - 降低输入分辨率 - 使用GPU加速 3. **推流断**: ```cpp // 添加重连机制 if (av_interleaved_write_frame(fmt_ctx, &pkt) < 0) { // 尝试重新初始化FFmpeg上下文 reinitialize_ffmpeg(); } ``` 4. **内存泄漏**: - 使用Valgrind检查内存泄漏 - 确保所有分配的资源都被正确释放 ## 部署建议 1. **模型优化**: - 使用ONNX格式的YOLO模型提高兼容性 - 量化模型减小尺寸 2. **推流协议选择**: - RTMP:广泛兼容,适合直播平台 - RTSP:更适合局域网流媒体 - SRT:抗网络抖动,适合不稳定网络 3. **容器化部署**: ```dockerfile FROM ubuntu:20.04 RUN apt-get update && apt-get install -y \ build-essential cmake libopencv-dev \ libavcodec-dev libavformat-dev libswscale-dev COPY . /app WORKDIR /app RUN cmake . && make CMD ["./yolo_streamer"] ``` ## 相关问题 1. **如何优化YOLO模型在嵌入式设备上的推理速度?** 可以考虑模型量化、剪枝和硬件加速技术[^2] 2. **RTMP和RTSP协议在推流实现上有哪些主要区别?** RTMP使用TCP协议,端口1935,适合直播;RTSP使用UDP/TCP,端口554,更适合点播场景[^1] 3. **如何在推流过程动态调整视频质量?** 可以通过监控网络状况动态修改编码器的比特率和分辨率参数 4. **如何为推流添加音频同步?** 需要使用`av_rescale_q()`同步音视频时间戳,并创建单独的音频流 5. **FFmpeg推流时如何添加水印或文字叠加?** 可以在OpenCV绘制阶段添加水印,或使用FFmpeg的filter_complex功能
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值