自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

一蓑烟雨任平生 也无风雨也无晴

白云一片去悠悠 青枫浦上不胜愁

  • 博客(648)
  • 资源 (3)
  • 问答 (4)
  • 收藏
  • 关注

原创 WebRTC Native M96 SDK接口封装--本地音频录制(纯音频)startAudioRecording开始客户端录音

此前已经说道,通过注册回调,给上层APP抛音频裸数据:上一篇文章,我们已经实现了混音回调:onMixedAudioFrame。本篇我们要在实现纯音频录制接口: startAudioRecording。

2022-12-21 17:33:00 4755 2

原创 WebRTC Native M96 回调音频裸数据IAudioFrameObserver--采集和播放语音混音后的数据(onMixedAudioFrame)

此前已经说道,通过注册回调,给上层APP抛音频裸数据:《WebRTC Native M96 SDK接口封装–注册语音观测器对象获取原始音频数据registerAudioFrameObserver》[https://dabaojian.blog.csdn.net/article/details/128218542]此篇,就详细讲述一下,如果实现onMixedAudioFrame。

2022-12-09 14:40:20 4922

原创 WebRTC Native M96 回调音频裸数据IAudioFrameObserver-播放的音频(onPlaybackAudioFrame)

上篇已经说道,通过注册回调,给上层APP抛音频裸数据:《WebRTC Native M96 SDK接口封装–注册语音观测器对象获取原始音频数据registerAudioFrameObserver》[https://dabaojian.blog.csdn.net/article/details/128218542]此篇,就详细讲述一下,如果实现onPlaybackAudioFrame。

2022-12-08 19:06:09 700

原创 WebRTC Native M96 回调音频裸数据IAudioFrameObserver--采集的音频(onRecordAudioFrame)

上篇已经说道,通过注册回调,给上层APP抛音频裸数据:《WebRTC Native M96 SDK接口封装–注册语音观测器对象获取原始音频数据registerAudioFrameObserver》[https://dabaojian.blog.csdn.net/article/details/128218542]此篇,就详细讲述一下,如果实现onRecordAudioFrame。AudioFrame的定义,这里就不在重复了,可以看上一篇博客。上文书说道,上层APP已经给我们SDK设置了回调函数,并且我

2022-12-08 00:30:00 4371

原创 WebRTC Native M96 SDK接口封装--注册语音观测器对象获取原始音频数据registerAudioFrameObserver

很多时候,上层app需要获取RTC中的音频数据,比如获取RTC麦克风采集的裸数据、扬声器播放的混音之后的裸数据,再比如麦克风和扬声器混音后的裸数据等等。在实时音视频中,用户可以对采集到的音频数据进行前处理和后处理,获取自己想要的播放效果,例如变音、录音等等。那么就需要上层APP向RTC SDK注册一个观测器,也就是我们所说的callback,订阅音频数据输出该方法用于注册音频观测器对象,即注册回调。当需要 SDK 给出 onMixedAudioFrame、onRecordAudioFrame、onPlay

2022-12-07 13:14:03 6979

原创 WebRTC Native M96收集网卡地址信息以及筛选过滤VPN网络(CreateNetworks、FilterNetworks)

网络类型很多,比如网线、WIFI、蜂窝网络、VPN、LOOPBACK等等。那么WebRTC在连接的时候,就可以对网络进行筛选,尤其是对于多网卡,多种连接方式的设备。WebRTC 收集网卡信息的时机线程: signaling thread线程: network thread在StartUpdating()中,向消息队列抛一个消息:kUpdateNetworksMessage接收到 KUpdateNetworksMessage 后调用 BasicNetworkManager::UpdateNetwor

2022-07-12 21:51:37 9695

原创 WebRTC Native M96编码规范向导(C++ C Python Java Oc Gn)

https://webrtc.googlesource.com/src.git/+/17071682f7fa70589e194b5882b43c611d055c74/style-guide.mdWebRTC遵循Chromium和Google C++ type的编码规范,如果两者有冲突,那么请参照Chromium的编码规范。《Chromium C++ style guide》《Google C++ Style Guide》WebRTC使用C++11:.h和.cc要成对的出现,并且使用同样的名字,在相同的文

2022-06-24 19:08:47 10518 1

原创 WebRTC Native M96 基础Base模块介绍之网络相关的封装

与版本无关的 IP 地址类,包装了 in_addr 和 in6_addr 的联合。对IP地址的封装IPAddress和InterfaceAddress,IPAddress重载了==、!=、、地址支持string()、sensitive_string()和uint32_t(AF_INET)()类型输出,还支持IPV4转IPV6类型()。InterfaceAddress是IPAddress的子类(),增加了IPv6属性()使用:还提供一些方法,比如字符串转IP:rtc_base SocketAddr...

2022-06-23 19:17:58 5071

原创 WebRTC Native M96 基础Base模块介绍之实用方法的封装(MD5、Base64、时间、随机数)

实现了多种类型的消息摘要算法,DIGEST_MD5、DIGEST_SHA_1、DIGEST_SHA_224、DIGEST_SHA_256、DIGEST_SHA_384、DIGEST_SHA_512[];MD5:MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Aut

2022-06-22 09:49:42 1827

原创 WebRTC Native M96 基础Base模块介绍之字符串处理相关的封装

字符串相关操作是永恒的话题,c++的string类给我们提供很多字符串操作的方法,但是再具体的情况下,还需要自己实现一些字符串的组装、格式化、转换等。rtc::GetStringFromJsonObject使用:rtc::StringBuilder使用:rtc::StringFormat使用:rtc::ToString的使用:rtc_base crypt_strings封装了一个加密字符串CryptString,加密字符串的字符可以是任意字符使用:rtc_base string_encode

2022-06-20 10:32:00 2821

原创 WebRTC Native M96 基础Base模块介绍之缓冲区相关的封装(CopyOnWriteBuffer、ByteBufferWriter、BitBufferWriter、BufferT、Buf

在WebRTC中,不论是发送接收数据通道的数据、还是发送接收音视频数据,数据本身都存储于一个临时的Buffer中,这个Buffer的实现类为CopyOnWriteBuffer。顾名思义,该Buffer实现了 “写时复制” 的技术。封装了一个写时复制缓存CopyOnWriteBuffer,其实就是封装了一个共享指针Buffer以及处理nullptr Buffer的情况,WebRTC中常用于RTP包的传递。Copy-on-write 主要用于共享操作系统进程的虚拟内存,在 fork 系统调用的实现中。通常,该进

2022-06-16 20:17:08 2201

原创 WebRTC Native M96 H264打包方式解读--kH264SingleNalu、kH264StapA、kH264FuA

在中介绍了WebRTC中H264的相关知识,这边不再啰嗦。抓了一个rtp的包:RTP包headerV:RTP协议的版本号,占2位,当前协议版本号为2Version: (2 bits) Indicates the version of the protocol. Current version is 2.P:填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。P (Padding): ...

2022-06-14 20:04:22 5842

原创 WebRTC Native M96 SDK接口封装--setLogFile设置 SDK 输出的日志文件

日志,是排查问题的主要手段。WebRTC自己带有日志模块,但是不够灵活,我们需要上层自己封装一层,提供成接口供上层调用。比如,设置日志生成的位置,设置日志的大小,以及设置日志的等级。...

2022-06-09 12:44:51 3752 1

原创 WebRTC Native M96视频基础知识介绍--使用H264

名词解释视频泛指将动态影像以电信号方式加以捕捉、纪录、处理、存储、发送与重现的各种技术。视频格式视频是现在电脑中多媒体系统中的重要一环。为了适应储存视频的需要,人们设定了不同的视频文件格式以将视频和音频放在一个文件中,以方便同时播出。什么3gp、mp4、avi啊,这些视频格式,从中学时代就有听说。首先,MP4、AVI、MKV都是本地视频文件的后缀,在windows系统下,用于提示操作系统应该采用哪个应用程序打开。而在流媒体领域,这些都被称为『视频封装格式』视频协议是针对网络流媒体而言的,也

2022-04-27 23:11:47 17407

原创 WebRTC Native M96音频基础知识介绍--使用Opus

声波声音是振动产生的声波,通过介质(气体、固体、液体)传播并能被人或动物听觉器官所感知的波动现象。声音的特性可由三个要素来描述,即响度、音调和音色音频(音调)音调就是音频。物理学中用每秒内振动的次数–频率来描述物体振动的快慢。物体振动的快(即频率高)则音调高,物体振动的慢(及频率低)则音调低。声音的频率一般会以赫兹表示,记为Hz,指每秒钟周期性震动的次数音量(响度)响度就是声音的大小强弱。取决于物体振动的幅度分贝是用来表示声音强度的单位,记为dB。数字音频数字音频是指使用脉冲编码调制、.

2022-04-26 23:50:39 3802

原创 WebRTC Native M96 SDK接口封装--muteRemoteVideoStream接收/停止接收指定远端用户的视频流

之前,介绍了如何实现muteLocalVideoStream和muteLocalAudioStream。接口定义(Agora)接口名:   muteRemoteVideoStream接口定义:virtual int agora::rtc::IRtcEngine::muteRemoteVideoStream(uid_t userId, bool mute) 接口功能:   接收/停止接收指定远端用户的视频流。注解: 

2022-04-06 21:50:28 9283

原创 WebRTC Native M96 SDK接口封装--muteLocalAudioStream开关本地音频发送

摊牌了,水了一篇。因为之前介绍了muteLocalVideoStream接口的实现,那么实现muteLocalAudioStream就大同小异了。接口定义(Agora)接口名:   muteLocalAudioStream接口定义:virtual int agora::rtc::IRtcEngine::muteLocalAudioStream(bool mute)接口功能:   开关本地音频发送。  &nb

2022-03-24 21:49:24 20146

原创 WebRTC Native M96 SDK接口封装--muteLocalVideoStream开关本地视频发送

https://dabaojian.blog.csdn.net/article/details/123587207已经介绍了如何开关本地预览,现在介绍一下mute/unmute本地音视频设备的接口。比如,实时直播课课间休息,老师想要干一点自己的事情,例如,对着摄像头补妆一下,但是又不想被学生看到。这个时候可以调用muteLocalVideoStream接口,本地的摄像头还依然在采集的数据,本地预览还是正常的,只是采集的视频数据不发送到远端用户。所以,这么分析之后,比较明朗了,这个接口,不需要操作硬

2022-03-24 21:47:02 8687

原创 WebRTC Native M96 SDK接口封装--startPreview开启视频预览

今天聊的事儿,跟peer connection一点关系没有,只是开启本地预览。在没有进行任何网络连接的时候,用户也可以先把本地的摄像头打开,孤芳自赏一下。如何枚举视频设备,已经介绍过了:https://dabaojian.blog.csdn.net/article/details/123511090如何设置本地和远端的视频显示视图,也已经介绍过了:接口定义(Agora)接口名:startPreview接口定义:virtual int agora::rtc::IRtcEngine::start.

2022-03-18 23:51:48 3921

原创 WebRTC Native M96数据统计-- 使用PeerConnection::GetStats获取WebRTC实时统计信息

ShineMo Demohttps://rtc.api.zhlh.sinopec.com/web端可以使用以下功能来看数据统计:chrome://webrtc-internals/chrome://webrtc-internals/https://rtc.api.zhlh.sinopec.com/下面介绍native端的数据统计!!!监控打点的意义实时音视频通话受网络状态影响很大,网络丢包延时都会导致视频通话质量。受设备性能影响也很大,CPU或者内存使用率高,可能导致音视频编解码卡顿。

2022-03-17 21:15:24 1164

原创 WebRtc Native M96 远端视频接收之-VideoReceiveStream2中FrameBuffer原理(6)

经过一系列的操作,最终完整的frame回到RtpVideoStreamReceiver2::OnCompleteFrames中。并且,通过complete_frame_callback_->OnCompleteFrame(std::move(frame));回调到VideoReceiveStream2类中。这时候,就需要frame_buffer_出场了!!!std::unique_ptr<video_coding::FrameBuffer> frame_buffer_;当组帧完.

2022-03-15 22:25:04 787

原创 WebRTC Native M96 SDK接口封装--setDevice指定视频设备

生活继续前一篇写了如果枚举视频设备,这里就谈一谈如何设置设备。在实际使用过程中,有的设备有多个视频采集设备,这个时候,用户可以自己选择自己需要使用哪个一个摄像头。这样,就需要先枚举设备,给用户一个设备列表,然后用户选择一个设备,通过接口设置到WebRTC中。奇怪:这里需要注意一下,声网的接口叫setDevice,而不是setVideoDevice。接口定义(Agora)接口名:setDevice接口定义:virtual int agora::rtc::IVideoDeviceManag.

2022-03-15 20:28:06 1559

原创 WebRTC Native M96 SDK接口封装--enumerateVideoDevices获取系统中所有的视频设备列表

不管怎样,活着便是盛宴!!!设备管理是重要的一环,在用户的实际使用过程中,会遇到各种各种的设备问题。这里,讲一下如何枚举系统中的所有的视频设备列表。接口定义(Agora)接口名:enumerateVideoDevices接口定义:virtual IVideoDeviceCollection* agora::rtc::IVideoDeviceManager::enumerateVideoDevices()接口功能:获取系统中所有的视频设备列表。参数:无返回:一个包含系统中所有视频设.

2022-03-15 20:19:37 5285

原创 WebRTC Native M96 SDK接口封装--setupLocalVideo、setupRemoteVideo设置本地(远端)视图

稀里糊涂介绍了一堆,那么怎么显示本地视频和远端视频呢?当然,有两种方式:1.SDK内部渲染,应用给SDK设置一个view,由SDK完成渲染2.由应用自己渲染,通过onCaptureVideoFrame将本地摄像头采集的数据回调给应用,通过onRenderVideoFrame将远端视频数据回调给应用,由应用自己显示这里,主要介绍第一种方法!!!!接口定义(Agora)接口名:setupLocalVideo()和setupRemoteVideo()接口定义:virtual int rtc::I

2022-03-14 22:10:29 2098

原创 WebRTC Native M96 SDK接口封装--setVideoEncoderConfiguration设置本地视频的编码属性

一系列云里雾里的介绍,最终还要回到接口的封装。提供接口,给上层应用调用。今天,就聊一聊setVideoEncoderConfiguration,设置本地视频编码属性接口的实现。接口定义(Agora)接口名:setVideoEncoderConfiguration()接口定义:virtual int IRtcEngine::setVideoEncoderConfiguration(const VideoEncoderConfiguration & config) 接口功能:设置视频

2022-03-14 22:07:08 10336

原创 WebRtc Native M96 远端视频接收之RtpFrameReferenceFinder-设置参考帧(5)

PacketBuffer:做报文缓存,根据帧开始、结束等标志,结合帧内seq的连续性,组成seq连续的一帧。此时需要确保其参考的帧也是组出来了,它才能送过去解码。H264目前是根据start bit以及Rtp Mark标志判断一帧开始和结束,在丢包等场景还需要结合timestamp来区分不同帧。(https://dabaojian.blog.csdn.net/article/details/123364413)RtpFrameReferenceFinder:帧参考关系寻找。packet buffer输出.

2022-03-09 22:31:50 1636

原创 WebRtc Native M96 远端视频接收之PacketBuffer-组帧原理分析(4)

组帧视频一帧数据往往被拆分为多个packet进行发送,组帧是将接收到的packets重组为视频帧。组帧的关键在于找到视频帧的起始与终止packet。对于h264编码的视频帧,rtp传输时没有明确的起始标志,webrtc在处理时以判断连续序列号的时间戳是否相同为依据,若不相同则认为找到了视频帧的起始packet。视频帧的结束标识为rtp包的header中的Mark标志位。对于vp8、vp9则可以从rtp包中解析到明确的帧开始与结束标识符。组帧结束后,拿到完整的视频帧数据,之后对该视频帧数据进行参考帧信息设置

2022-03-08 22:00:51 3478

原创 WebRtc Native M96 远端视频接收之NackRequester、NackSender-NACK丢包重传原理(3)

WebRTC NACK is Negative Acknowledgement. One of the mechanisms for delivery errors correction in WebRTCrtp包是如何到达NackRequester模块的注意,在M96版本中,类名是NackRequesterCall::DeliverPacketCall::DeliverRtpRtpStreamReceiverController::OnRtpPacketRtpDemuxer::OnRtpPa

2022-03-08 21:58:13 614

原创 WebRtc Native M96 远端视频接收之RtpVideoStreamReceiver2-RTP包接收流程分析(2)

rtp包是如何到达Call模块的从网络接收包,到达WebRtcVideoChannel::OnPacketReceivedUDPPort::HandleIncomingPacketUDPPort::OnReadPacketConnection::OnReadPacketP2PTransportChannel::OnReadPacketDtlsTransport::OnReadPacketRtpTransport::OnReadPacketSrtpTransport::OnRtpPacketR

2022-03-07 22:05:52 958

原创 WebRtc Native M96 远端视频接收之VideoReceiveStream2模块创建分析(1)

从设置remote sdp开始从pc模块的channel到media engine模块的AddRecvStream别蒙圈,先看看BaseChannel和VideoChannel啥关系?这里注意,BaseChannel类所在的文件的文件名是channel.cc。VideoChannel重写了SetRemoteContent_w方法class BaseChannel : public ChannelInterface, public sigslot::has_

2022-03-07 22:00:57 1135

原创 WebRTC Native M96 SDK接口封装--enableLoopbackRecording启用声卡采集,声卡播放的声音合到本地音频流发送远端

音频采集或播放时,需要用MMDevice API来枚举和获取指定设备,用WASAPI来处理应用程序和音频设备之间的音频流数据,如采集或播放声网接口:enableLoopbackRecording接口:virtual int agora::rtc::IRtcEngine::enableLoopbackRecording (bool enabled, const char * deviceName = NULL)功能:开启声卡采集启用声卡采集功能后,声卡播放的声音会被合到本地音频流中,从而可

2022-02-23 22:48:11 1452

原创 WebRTC Native M96 SDK接口封装--startAudioMixing播放音乐文件与麦克风采集声音混音

封装接口使用WebRTC大概有两种方式,一种是把WebRTC当做一种库来用;另一种是把WebRTC当做一个框架,自己在上层封装代码。不管怎么,做实时音视频SDK开发的,都需要封装接口,供给上层应用调用。在国内,声网的用户比较多,社区做的也比较好,所以很多公司的RTC SDK的接口设计都会仿造声网。这样做有很多的好处:不用自己写demo,直接使用agora的openlive。便于跟agora对标,向agora看齐,无论是产品功能上,还是音视频质量上。对于上层接入来说,如果做到接口一样,那么不管

2022-02-22 22:31:51 5206 1

原创 WebRTC Native M96中的基本音频处理操作(AudioState、AudioProcessing、AudioMixer)

之前写了音频发送流程以及接收音频包播放流程(https://dabaojian.blog.csdn.net/article/details/122991836),总感觉不太通透。那就继续聊聊基本的音频处理操作吧!!WebRTC 音频引擎建立之后,其相关节点状态由 AudioState 维护和管理。WebRTC 音频處理流程,主要包括 AudioDeviceModule,AudioProcessing,和 AudioMixer 等其中:AudioDeviceModule 用于采集和播放音频数据A.

2022-02-22 22:26:42 843

原创 WebRTC Native M96 视频发送编码(OpenH264)流程以及接收视频包解码(FFmpeg)播放流程

H264 和 OpenH264H.264,又称为MPEG-4第10部分,高级视频编码(英语:MPEG-4 Part 10, Advanced Video Coding,缩写为MPEG-4 AVC)是一种面向块,基于运动补偿的视频编码标准 。到2014年,它已经成为高精度视频录制、压缩和发布的最常用格式之一。第一版标准的最终草案于2003年5月完成。H.264/AVC项目的目的是为了创建一个更佳的视频压缩标准,在更低的比特率的情况下依然能够提供良好视频质量的标准(如,一半或者更少于MPEG-2,H.263

2022-02-18 23:50:47 2967

原创 WebRTC Windows Native视频中的DirectShow介绍

WebRTC视频采集WebRTC视频采集,不同的平台由不同的公司开发设计:Linux系统使用V4L2(Video for Linux Version 2)Mac和IOS都是苹果公司开发的,都使用AVFoundation框架Windows使用的是微软开发的DS(Direct Show)框架Android使用camera2.0接口(Camera2Capturer)采集视频。DirectShow(https://docs.microsoft.com/zh-cn/windows/win32/direct

2022-02-18 22:05:32 314678

原创 WebRTC Native M96 音频发送流程(SendRtp)以及接收音频包播放流程(OnPacketReceived)

WebRTC默认是采用Opus编码。Opus是一个有损音频压缩的数字音频编码格式,由Xiph.Org基金会开发,之后由互联网工程任务组(IETF)进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用于网络上低延迟的即时声音传输,标准格式定义于RFC 6716文件。Opus格式是一个开放格式,使用上没有任何专利或限制。Opus集成了两种声音编码的技术:以语音编码为导向的SILK和低延迟的CELT。Opus可以无缝调节高低比特率。在编码器内部它在较低比特率时使用线性预测编码在

2022-02-17 20:59:15 1652

原创 WebRTC Windows Native音频中的Core Audio API

Core Audio API简介Core Audio API 包括:Multimedia Device (MMDevice) API :用这些 API 来枚举系统中的音频设备。Windows Audio Session API (WASAPI) :用这些 API 来创建和管理来自音频设备音频流。DeviceTopology API :用这些 API 来直接访问声音适配器中的硬件数据通路的拓扑特性(如音量控制,复用器等)EndpointVolume API :用这些 API 直接访问音频设备的声

2022-02-16 22:43:21 13631

原创 WebRTC 视频编解码类型的选择 VP8 H264 还是其他?(openh264编码,ffmpeg解码)

在你的WebRTC应用中,选择正确的视频编解码器很重要,但是如何选择又是一个棘手的问题。WebRTC 视频编解码器 –简要回顾WebRTC 曾经很容易。你有 VP8、Opus 和 G.711。 G.711 被删除是因为我不想让你使用它。真的没有理由这样做。后来,H.264 被添加为强制实现视频编解码器。在 WebRTC 的世界里一切都很好。谷歌随后决定在 Chrome 中引入 VP9。作为可选编解码器。 Mozilla 也将 VP9 添加到 Firefox。微软当他们..

2022-02-16 21:58:01 1964 1

原创 WebRTC Native中的线程模型

WebRTC中的基本线程为了降低系统的复杂性,提高系统的运行效率,WebRTC 设计了一套多线程框架,并且做了精心的设计。主要包括三个线程:rtc::Thread* network_thread;rtc::Thread* worker_thread;rtc::Thread* signaling_thread;network_thread网络线程(Network thread )主要是工作在传输(transport)层,具体工作如下:Transport 的初始化从网络接收数据,发送给

2022-02-16 21:46:22 650

原创 如何开始WebRTC Native 跨平台开发的学习之旅?

某位哲人说过:WebRTC is a new front in the long war for an open and unencumbered web.另一位哲人说过:21世纪是达芬奇的世纪,也是WebRTC的世纪看看领英上,提到WebRTC的增长:问题如果,你学习 WebRTC 开发已经有一段时间了,也可能已经看过 AppRTC 或从 github 获取了一段代码,运行您自己搭建的环境。但是现在你感觉卡住了,无法成为一名认真的 WebRTC 开发人员。...

2022-02-16 21:31:33 712

duilib开发dll、lib、头文件等

进行duilib开发需要的所有的dll、lib、头文件等

2015-09-02

2015年阿里巴巴面试题完美解决

2015年阿里巴巴实习生招聘,最难理解的一道算法题,完美解决

2015-04-04

重载时自增(自减)的前缀和后缀的区别

对于自增(自减)运算,前缀和后缀的优先级有所不同。在重载时候,前缀自增和后缀自增的方法也不相同,本代码详细阐述了两者的区别所在。开发平台VS2010

2014-10-25

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除