远生网络视频会议源码揭秘!

yeyuanzhi2000 2011-10-08 01:58:21
加精
远生专业视频会议是比较成熟的视频会议,http://download.csdn.net/detail/yeyuanzhi2000/3653285有演示版下载,现将部分源码公开,以后将陆续揭秘。供各位学习参考:
BOOL CDlgVideoConfig::OnInitDialog() 
{
CDialogMultiLan::OnInitDialog();

// TODO: Add extra initialization here
m_btnProperty.SubclassDlgItem(IDC_BTN_VIDEOPROPERTY,this);
m_btnPicProperty.SubclassDlgItem(IDC_BTN_PICPROPERTY,this);
m_btnPicProperty.ShowWindow( SW_HIDE );

m_cbVideoSize.ResetContent();
//
m_cbVideoSize.AddString("160 * 120");
m_cbVideoSize.AddString("176 * 144");
m_cbVideoSize.AddString("320 * 240");
m_cbVideoSize.AddString("352 * 288");
#ifndef VIDEO_CIF //高清版
m_cbVideoSize.AddString("640 * 480");
#ifndef VIDEO_HR
m_cbVideoSize.AddString("704 * 576");
m_cbVideoSize.AddString("720 * 576");
#endif
#endif

CString strText;
g_lanManager.ReadTableString( IDS_CONTROL_VBRMODE,strText );
int nIndex = m_cbEncodeMode.AddString( strText );
m_cbEncodeMode.SetItemData( nIndex,0 );
g_lanManager.ReadTableString( IDS_CONTROL_CBRMODE,strText );
nIndex = m_cbEncodeMode.AddString( strText );
m_cbEncodeMode.SetItemData( nIndex,1 );


LoadConfig();

VIDEO_GetDefImgProcSetting( m_imgFilterSetting );

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}

void CDlgVideoConfig::LoadConfig()
{
switch(g_config.m_videoConfig.nVideoSize){
case 0:
m_nVideoWidth = 160;
m_nVideoHeight = 120;
break;
case 1:
m_nVideoWidth = 176;
m_nVideoHeight = 144;
break;
case 2:
m_nVideoWidth = 320;
m_nVideoHeight = 240;
break;
case 3:
m_nVideoWidth = 352;
m_nVideoHeight = 288;
break;
case 4:
m_nVideoWidth = 640;
m_nVideoHeight = 480;
break;
case 5:
m_nVideoWidth = 704;
m_nVideoHeight = 576;
break;
case 6:
m_nVideoWidth = 720;
m_nVideoHeight = 576;
break;
default:
g_config.m_videoConfig.nVideoSize = 2;
m_nVideoWidth = 320;
m_nVideoHeight = 240;
break;
}

//缺省视频大小
m_cbVideoSize.SetCurSel(g_config.m_videoConfig.nVideoSize);
m_chkImgProc.SetCheck( g_config.m_videoConfig.bEnableImgProc );
m_chkOVerlay.SetCheck( g_config.m_videoConfig.bUseOverlay );

//最大码流
m_sliderBitRate.SetRange(0,2048);
m_sliderBitRate.SetPageSize( 10 );
m_sliderBitRate.SetLineSize( 10 );

if(g_config.m_videoConfig.nBitRate == 0)
g_config.m_videoConfig.nBitRate = 128;

m_sliderBitRate.SetPos( g_config.m_videoConfig.nBitRate );


for (int i=0;i<m_comRade.GetCount();i++)
{
CString strTemp;
m_comRade.GetLBText(i, strTemp);
strTemp.Replace("Kpbs","");
if (atoi(strTemp.GetBuffer(0)) == g_config.m_videoConfig.nBitRate)
m_comRade.SetCurSel(i);
}

CString strBitRate;
strBitRate.Format("%dKbps",g_config.m_videoConfig.nBitRate );
SetDlgItemText( IDC_STATIC_BITRATE,strBitRate);


//视频采集设备
m_cbVideoCapturer.ResetContent();
CString strDevice;
CStringList lstVDevices;
VIDEO_EnumDevices(lstVDevices);
POSITION pos = lstVDevices.GetHeadPosition();
while(pos){
strDevice = lstVDevices.GetNext(pos);
int nIndex = m_cbVideoCapturer.AddString(strDevice);
}
lstVDevices.RemoveAll();
//如果没有找到上次保存的设置ID,则设置第一个设备为默认设备
if( m_cbVideoCapturer.GetCount() > 0 ){
if( m_cbVideoCapturer.GetCount() > g_config.m_videoConfig.nVideoCapture
&& g_config.m_videoConfig.nVideoCapture >= 0)
m_cbVideoCapturer.SetCurSel( g_config.m_videoConfig.nVideoCapture );
else{
m_cbVideoCapturer.SetCurSel( 0 );
g_config.m_videoConfig.nVideoCapture = 0;
}
}

m_cbVideoEncoder.ResetContent();
CString strEncoder;
CStringList lstEncoders;
VIDEO_EnumEncoders(lstEncoders);
pos = lstEncoders.GetHeadPosition();
while(pos){
strEncoder = lstEncoders.GetNext(pos);
int nIndex = m_cbVideoEncoder.AddString(strEncoder);
}
lstEncoders.RemoveAll();
//设置默认压缩器
if( m_cbVideoEncoder.GetCount() > 0 ){
if( m_cbVideoEncoder.GetCount() > g_config.m_videoConfig.nVideoEncoder
&& g_config.m_videoConfig.nVideoEncoder >= 0)
m_cbVideoEncoder.SetCurSel( g_config.m_videoConfig.nVideoEncoder );
else{
m_cbVideoEncoder.SetCurSel( 0 );
g_config.m_videoConfig.nVideoEncoder = 0;
}
}

//设置默认压缩模式
if( m_cbEncodeMode.GetCount() > 0 ){
if( m_cbEncodeMode.GetCount() > g_config.m_videoConfig.nVideoEncodeMode
&& g_config.m_videoConfig.nVideoEncodeMode >= 0)
m_cbEncodeMode.SetCurSel( g_config.m_videoConfig.nVideoEncodeMode );
else{
m_cbEncodeMode.SetCurSel( 0 );
g_config.m_videoConfig.nVideoEncodeMode = 0;
}
}

m_cbVideoInput.EnableWindow(m_cbVideoInput.GetCount() > 0);

//视频轮循
SetDlgItemInt(m_editVideoPoll.GetDlgCtrlID(), g_config.m_videoConfig.nVideoPollTime);


}

void CDlgVideoConfig::StartVideoDevices()
{
VIDEO_EnablePostProc( g_config.m_videoConfig.bEnableImgProc );
VIDEO_EnableOverlay( FALSE );
m_bHasVideo = StartVideoCapDevices();
VIDEO_SMGR_SetBitRate( g_config.m_videoConfig.nBitRate );
if (m_bHasVideo)
SMNotifyBox1("初始化视频设备成功。");
}

BOOL CDlgVideoConfig::StartVideoCapDevices()
{
m_cbVideoInput.EnableWindow( FALSE );
m_cbVideoInput.ResetContent();

BOOL bRet = VIDEO_SMGR_StartCapture( g_config.m_videoConfig.nVideoCapture,
g_config.m_videoConfig.nVideoEncoder,
g_config.m_videoConfig.nVideoEncodeMode,
g_config.m_videoConfig.nBitRate,
m_nVideoWidth,
m_nVideoHeight,
"dkalsdfag-asffdg-asdqr-sdfg-adf");

if( !bRet ){
SMNotifyBox1(IDS_ERROR_OPENVIDEO);
return FALSE;
}

CString strSource;
CStringList lstVideoSource;
int count = VIDEO_SMGR_GetVideoSource(lstVideoSource);
if( count > 0 ){

POSITION pos = lstVideoSource.GetHeadPosition();
while(pos){
strSource = lstVideoSource.GetNext(pos);
int nIndex = m_cbVideoInput.InsertString(-1,strSource);
}
lstVideoSource.RemoveAll();

m_cbVideoInput.EnableWindow( TRUE );
g_config.m_videoConfig.nVideoInput = g_config.m_videoConfig.nVideoInput >= count?0:g_config.m_videoConfig.nVideoInput;
m_cbVideoInput.SetCurSel( g_config.m_videoConfig.nVideoInput );
VIDEO_SMGR_SetVideoSourceIndex( g_config.m_videoConfig.nVideoInput );
}

return TRUE;
}

void CDlgVideoConfig::SaveConfig()
{
UpdateData( TRUE );
m_bHasVideo = g_userManager.HasVideoDevice(g_globalInfo.dwUserID);


CString strVideoCapture;

//video capture
int nVideoSel = max(m_cbVideoCapturer.GetCurSel(), 0);

int nVideoEncoder = max(m_cbVideoEncoder.GetCurSel(), 0);

int nEncodeMode = max(m_cbEncodeMode.GetCurSel(), 0);

int nVideoInput = max(m_cbVideoInput.GetCurSel(), 0);


switch(m_nVideoSize){
case 0:
m_nVideoWidth = 160;
m_nVideoHeight = 120;
break;
case 1:
m_nVideoWidth = 176;
m_nVideoHeight = 144;
break;
case 2:
m_nVideoWidth = 320;
m_nVideoHeight = 240;
break;
case 3:
m_nVideoWidth = 352;
m_nVideoHeight = 288;
break;
case 4:
m_nVideoWidth = 640;
m_nVideoHeight = 480;
break;
case 5:
m_nVideoWidth = 704;
m_nVideoHeight = 576;
break;
case 6:
m_nVideoWidth = 720;
m_nVideoHeight = 576;
break;
default:
m_nVideoSize = 2;
m_nVideoWidth = 320;
m_nVideoHeight = 240;
break;
}

int nBitRate = m_sliderBitRate.GetPos();
CString strTemp;
m_comRade.GetWindowText(strTemp);
strTemp.Replace("Kpbs","");

nBitRate = atoi(strTemp.GetBuffer(0));


BOOL bUserOverlay = m_chkOVerlay.GetCheck();
if( bUserOverlay != g_config.m_videoConfig.bUseOverlay ){
g_config.m_videoConfig.bUseOverlay = bUserOverlay;
VIDEO_EnableOverlay( bUserOverlay );
}

//图象后处理
BOOL bEnableImgProc = m_chkImgProc.GetCheck();
if (bEnableImgProc != g_config.m_videoConfig.bEnableImgProc);
{
g_config.m_videoConfig.bEnableImgProc = bEnableImgProc;
VIDEO_EnablePostProc(bEnableImgProc);
}

//改变视频采集设备或采集大小
if( nVideoSel != g_config.m_videoConfig.nVideoCapture ||
g_config.m_videoConfig.nVideoSize != m_nVideoSize ||
g_config.m_videoConfig.nVideoEncoder != nVideoEncoder ||
g_config.m_videoConfig.nVideoEncodeMode != nEncodeMode ){

g_config.m_videoConfig.nVideoSize = m_nVideoSize;
g_config.m_videoConfig.nVideoCapture = nVideoSel;
g_config.m_videoConfig.nVideoEncoder = nVideoEncoder;
g_config.m_videoConfig.nVideoEncodeMode = nEncodeMode;
m_bHasVideo = StartVideoCapDevices();

}else{

if( nVideoInput != g_config.m_videoConfig.nVideoInput && m_cbVideoInput.GetCount()>0 ){
g_config.m_videoConfig.nVideoInput = nVideoInput;
VIDEO_SMGR_SetVideoSourceIndex( nVideoInput );
}
}

g_config.m_videoConfig.nVideoPollTime = m_nVideoPollTime;

//设置最大码流
if( nBitRate != g_config.m_videoConfig.nBitRate ){
g_config.m_videoConfig.nBitRate = nBitRate;
VIDEO_SMGR_SetBitRate( g_config.m_videoConfig.nBitRate );
}

// m_dlgCameraConfig.SaveConfig();
}

BYTE CDlgVideoConfig::GetVideoDevicesCount()
{
if( m_cbVideoCapturer.GetSafeHwnd() )
return (BYTE)m_cbVideoCapturer.GetCount();

return 0;
}

BOOL CDlgVideoConfig::CheckVideoDevice(BYTE bVideoDevice)
{
if( bVideoDevice < 0 || bVideoDevice >= GetVideoDevicesCount() )
return FALSE;

if( bVideoDevice == g_config.m_videoConfig.nVideoCapture )
return FALSE;

g_config.m_videoConfig.nVideoCapture = bVideoDevice;
m_bHasVideo = StartVideoCapDevices();
m_cbVideoCapturer.SetCurSel( bVideoDevice );

return TRUE;
}

BYTE CDlgVideoConfig::GetVideoDeviceIndex()
{
if( m_cbVideoCapturer.GetSafeHwnd() )
return (BYTE)m_cbVideoCapturer.GetCurSel();

return 0;
}

void CDlgVideoConfig::OnBtnPicproperty()
{
// TODO: Add your control notification handler code here
CDlgImgProcConfig dlg( &m_imgFilterSetting );
dlg.DoModal();
}

...全文
7751 180 打赏 收藏 转发到动态 举报
写回复
用AI写文章
180 条回复
切换为时间正序
请发表友善的回复…
发表回复
绿 2013-03-13
  • 打赏
  • 举报
回复
看到这个我又要mark一下了
Luo_Bryant 2013-03-08
  • 打赏
  • 举报
回复
学习了。。。
tyzqqq 2013-03-08
  • 打赏
  • 举报
回复
hzy694358 2013-03-08
  • 打赏
  • 举报
回复
楼主,这是客户端, 那服务端呢,服务端
Kaile 2013-03-06
  • 打赏
  • 举报
回复
这个项目花了几千万的风投 风投真有钱
浪人不浪 2013-03-06
  • 打赏
  • 举报
回复
不错 可以学习一下
LuciferStar 2013-03-05
  • 打赏
  • 举报
回复
这个系统最关键的,就是图像的压缩和传输。其它都没啥看头。
Vector_fz 2013-03-05
  • 打赏
  • 举报
回复
对H264部分感兴趣
Fields_Of_Gold 2013-03-05
  • 打赏
  • 举报
回复
谢谢楼主分享。。。
w1881 2012-01-07
  • 打赏
  • 举报
回复
支持,但是感觉跟连续剧一样,是不是有心赚人气啊
project15 2012-01-07
  • 打赏
  • 举报
回复
H264编码代码 的函数怎么都注释了
CoolVideo 2011-12-31
  • 打赏
  • 举报
回复
楼主的代码可能来源。互联天下--》瑞福特---》誉融。部分设备采集及视频编解码,还有云台的代码,是互联天下遗留下来的,到了瑞福特做了不少的完善及增加功能,WEB和白板,及屏幕广播貌似是这时候完善的。代码都没变过,连注释也是。P2P貌似是到誉融完善的。好歹这个项目花了几千万的风投。不过道最后,有能力的出国了,一般的在其他视频大公司混,不入流的就改改代码,套点闲钱,卖卖东西给政府这个冤大头用用。
modicum_ck 2011-12-31
  • 打赏
  • 举报
回复
mark...
xiaobaitu133 2011-12-30
  • 打赏
  • 举报
回复
学习学习,看看了,楼主辛苦了!!
useky 2011-11-22
  • 打赏
  • 举报
回复
支持开源。
StonesHeart 2011-11-22
  • 打赏
  • 举报
回复
我觉得要注释,呵呵,还是受益了,谢了。
Dcdu 2011-11-22
  • 打赏
  • 举报
回复
好东东,但不怎么看的懂
lijianli9 2011-11-20
  • 打赏
  • 举报
回复
是的,放到download中吧,
yeyuanzhi2000 2011-11-19
  • 打赏
  • 举报
回复
贴上来是让大家学习的,可不要不劳而获哦,这样就失去了论坛的意义了
w88529593 2011-11-19
  • 打赏
  • 举报
回复
直接放到下载资源里面,让大家下载得了
加载更多回复(160)
一、功能特点 1、基于 MPEG4的多媒体技术 采用MPEG4 标准的视频压缩技术,占用带宽比传统 H.323 视频会议系统更低。适应从 56Kbps 拨号上网到宽带等的各种网络环境,能提供清晰流畅的视频图像。 2、 同时支持的发言人数无限制,最大限度的满足会议需要 利用在业界领先的音频压缩技术,在国内首次研发出多人混音的音频效果。用户在开会过程中,所有与会者可以同时听见多个发言人的声音,让沟通更加流畅。 3、多路视频图像,随时切换任意参会者视频窗口 支持多路视频图像显示,可以同时显示 16 路视频图像,支持主会场大窗口显示;用户可以随意切换到其他用户的视频图像,或者选择一个视频窗口进行多级放大。 4、浏览器同步浏览 提供了浏览器协同浏览功能,参加会议的所有用户可以同步地浏览网页。只要用户的电脑上安装了 Windows 操作系统内含的 Internet Exploer 浏览器,所有的会议成员就可以同时访问同一个网站的同一个页面,并且,当您点击其中的任何一个超级链接,所有的与会者也能看见新打开的页面。同时所有的 Office 文档,都可以用同步浏览的方式,这些文档格式包括 Office 、 PDF 、 Visio 、 AutoCAD 、 Pagemaker 、 Photoshop 等各种形式的文档,象企业常用的财务报表,都可以实现远程共享。 5、云台控制 在本系统中,不仅可以遥控本机的摄像头,并且主持人还可以远程遥控任一会场的摄像头,可远程对摄像机镜头进行光圈、焦距、景深等控制。可以对云台进行全方位的控制。 6、视频轮循 可实现视频轮循的功能操作,并可设置轮询时间,适用于对各路视频的监控。 7 、文档共享,会议过程中协同讨论 可共享多种文档: PowerPoint 、 Word 、 Excel 、 PDF 、 Visio 、 AutoCAD 、 TXT 、 FLASH 及各种影音文件,而且主持人能在各种文档上做标注,主持人授权后,其他人也可以对文档进行修改、标注,实现远程协同办公,实时交流; 8 录制播放功能 与会者可以实时同步录制会议内容,包括多路视音频数据和白板及文字聊天数据,录制的多媒体数据可以进行同步回放。 9 白板交互系统 与会者可以同时在白板上画图、写字、粘贴图片、粘贴编辑好的图形等,并且所有的人都能看到;会议主持人可以对白板使用权限进行控制,可以允许或禁止其他人使用白板。 10 文字交互系统 在文字讨论区,会议成员可以与全体人员或某个人进行文字交谈,当选择对一个人发送信息时,其他会议成员则不能看到。 11 、屏幕广播 会议用户可以把自己的计算机屏幕实时广播给其他用户,用户的操作步骤和屏幕图像同步显示在所有接收者的屏幕上,适合于演讲和教学。 12 、浏览器同步浏览 所有的会议成员可以同步地浏览网页,点击网页的任何一个超级链接,其他成员也同时打开新的页面浏览 13、界面友好,操作简便。系统界面直观、友好,用户无须任何培训便可进行熟练操作和灵活使用,体验音、视频交互和数据交流的强大功能。 14、适应各种网络环境:系统采取了多种机制保证在各种防火墙下都能有解决方案使得网上的视频会议能够无障碍的进行。支持 NAT 、代理服务器以及各种防火墙,大多数企业在应用时无需更改任何网络配置,就可以将系统部署到企业现有的网络环境中。 二、服务端设置 1、在SQL2000中附加数据库文件eb_Data.MDF、eb_Log.LDF。默认用户名sa,密码为空。 2、打开Server.exe,并双击右下角状态栏的服务端图标,选择设置选项进行IP设置。 3、设置完毕后,重启Server.exe服务端。 三、登录帐号和密码 用户名ok11至ok55,密码与用户名相同
EV-Meeting远生网络视频教学系统为纯软件高清视频会议产品。用户只需普通的PC机,麦克风,摄像头就能够轻松在互联网上召开网络会议。 一、功能介绍 1、视频功能:基于C/S架构,采用H264压缩算法,支持混音,可以多人同时说话,具有高清晰的图像。在具有独享 384K或以上带宽时,能为用户提供稳定的清晰视频图像;具备多种显示模式,双流合一功能;在自由模式下可以相互自由察看视频。32路数多种显示,最低带宽支持56K;不仅可以遥控本机的摄像头,并且主持人还可以远程遥控任意一会场的摄像头,可远程对摄像机镜头进行光圈、焦距、景深等控制;可以对云台进行全方位的控制。 2、音频功能:多人混音的音频效果。用户在开会过程中对用户的混音路数无限制,所有与会者可以同时听见多个发言人的声音,让沟通更加流畅。并且在并发的各会议室内都可以进行多路混音,并且各会议室之间相互不会产生干扰。 3、数据功能:白板功能支持使用手写笔直接在白纸上进行书写输入,其他所有会议成员可以在白板上同步接收并进行编辑修改。在文字讨论区,会议成员可以与全体人员或某个人进行文字交谈,当选择对一个人发送信息时,其他会议成员则不能看到。系统拥有丰富的数据共享功能,支持电子白板、文档共享、Web共享、协同浏览、桌面共享、文字讨论、资料分发等功能。 4、文字聊天:对全体或某人的文本聊天。支持表情和字体发送功能 5、电子白板:矢量表示,可任意编辑,支持doc、ppt、html以及图片功能。 6、文档共享:文件上传、下载,文档同步浏览。 7、同步浏览:浏览相同的网站页面。 8. 举手发言:每个会议人员可以举手申请发言和操作权,其权利由主持人决定。 9. 屏幕共享:将本机上的屏幕图像和鼠标操作等共享到其他会议人员的桌面上。 10、同步录制:同步录制视频、音频,计算机动态屏幕,即可将主讲人的图像、声音和所讲解的课件、讲稿、鼠标操作轨迹以及电子白板上书写的内容等计算机屏幕上所显示的内容同步录制到一个文件中。 11、实时直播:可通过单播或多播方式将现场的视频、音频、计算机动态屏幕在网络上进行实时直播,用户可通过系统客户端软件同步接收到现场的视频、音频和计算机动态屏幕信息。 12、支持NAT穿透技术,可以在任何复杂网络下运行。 13、演讲板:支持Office办公文件(ppt、doc、xls、txt等格式)、视频文件(mpg、mgeg、mp3、avi等格式)、Flash文件(swf格式)、图片文件等演示。 14、其他功能:会议投票功能。 二、系统要求 1、操作系统:Windows xp/2003/98 2、网络环境:在Internet和局域网中均可运行,最低带宽56K。 源码演示 http://video.sina.com.cn/v/b/111851167-2702263835.html
传统培训面临如下挑战:   1)实施成本高。   2)缺乏延续性。   3)资源利用不足。   4)培训覆盖面小。   5)间断员工的工作安排。   6)缺乏培训的效果管理。   7)缺乏统一的实施标准。   远程培训的优势:   网络远程培训克服了传统培训在时间、空间、环境等方面的限制,借助网络来进行多媒体培训,采用音频、视频和超文本等多种方式,传递培训信息,让优秀的资源得以共享,教员、学员和媒体之间实现自由地交流。   网络远程培训可以提供更有效、更及时、更有针对性的培训,培训时间和地点机动灵活,降低培训成本,将在岗学习和培训有机地结合在一起,扩展了企业/政府/院校人员学习的空间和途径,由传统的被动学习转变为主动有选择地学习,充分提高培训效率。   EV-Teaching远程培训平台简介:   EV-Teaching远程培训平台是广东远生网络开发有限公司利用自己多年的网络通讯开发积累的技术优势和对e-learning国内外行业应用标准的深刻理解而研发的产品化软件系统平台。   平台主要面向政府或企业推出包含课程管理、资料管理以及信息交流管理的综合多效解决方案,是政府或企业创建学习型组织的有效推广工具和企业级应用平台。   政府或企业可以方便地在内部或者互联网部署远生远程培训平台,利用平台丰富的管理功能,从而迅速组织学习、培训、调查、评价、知识管理、学习交流等活动,方便地开展内训和外训业务。   系统通过建立自由开放,便于信息共享交流和知识传播的快捷、平等的信息管理平台,保证广泛分布的学员能自由地取得学习、训练和培养自己的有效手段和途径。   平台提供了强大的网络交流功能,实现了集视频交互、音频交互、文字交流、电子白板、图像处理、文档共享、文件传输、协同浏览等多项功能于一体的综合多媒体远程教育系统。用户利用平台,可以很方便地开展实时的会议、讲座、答疑等多种教学模式。   远生网络平台是由培训网站和培训软件两部分组成。其中,培训网站是对内对外众多应用开展的基础或承载平台,其它大量业务应用如视频点播、网络视频会议等均基于网站来开展。培训软件包括一系列有我公司自主开发的软件,包括网络会议系统、即时通讯工具、课件制作器、课件播放器、学习记录管理器等。两部分相互配合,共同完成网络培训的各个功能。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧