赞
踩
WebRTC专题开嗨鸭 !!!
一、 WebRTC 线程模型
2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用
二、 WebRTC媒体协商
1、WebRTC媒体协商之SDP中JsepSessionDescription类结构分析
三、 WebRTC 音频数据采集
四、 WebRTC 音频引擎(编解码和3A算法)
五、 WebRTC 视频数据采集
六、 WebRTC 视频引擎( 编解码)
七、 WebRTC 网络传输
2、WebRTC的ICE之Dtls/SSL/TLSv1.x协议详解
八、 WebRTC服务质量(Qos)
3、WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传
九、 NetEQ
十、 Simulcast与SVC
WebRTC视频采集流程图
IPin::QueryDirection方法
HRESULT QueryDirection([out] PIN_DIRECTION* pPinDir);
参数1: 获取Pin的方向 PINDIR_INPUT/PINDIR_OUT
WebRTC中使用 IKsPropertySet::Get方法
HRESULT Get([in] REFGUID rguidPropSet/*要访问的属性集*/,
[in] ULONG ulId /*要访问的属性集中的某一项*/,
[out] LPVOID pInstanceData/*实例数据*/,
[out] ULONG ulInstanceLength/*实例数据长度*/,
[out] LPVOID pPropertyData/*读到的属性数据*/,
[out] ULONG ulDataLength/*存放属性数据的长度*/,
[out] PULONG pulBytesReturened/*真正读到的属性数据长度*/)
// Provides a reference count implementation for COM (IUnknown derived) classes. // The implementation uses atomics for managing the ref count. template <class T> class ComRefCount : public T { public: ComRefCount() {} template <class P0> explicit ComRefCount(P0&& p0) : T(std::forward<P0>(p0)) {} STDMETHOD_(ULONG, AddRef)() override { ref_count_.IncRef(); return 1; } STDMETHOD_(ULONG, Release)() override { const auto status = ref_count_.DecRef(); if (status == rtc::RefCountReleaseStatus::kDroppedLastRef) { delete this; return 0; } return 1; } protected: ~ComRefCount() {} private: webrtc::webrtc_impl::RefCounter ref_count_{0}; };
// Create the sink filte used for receiving Captured frames.
sink_filter_ = new ComRefCount<CaptureSinkFilter>(this);
input_pin_ = (new ComRefCount<CaptureInputPin>(this))
// 1、是一个Filter class ComRefCount : public CaptureSinkFilter { public: ComRefCount() {} explicit ComRefCount(VideoCaptureDS&& p0) : CaptureSinkFilter(std::forward<VideoCaptureDS>(p0)) {} STDMETHOD_(ULONG, AddRef)() override { ref_count_.IncRef(); return 1; } STDMETHOD_(ULONG, Release)() override { const auto status = ref_count_.DecRef(); if (status == rtc::RefCountReleaseStatus::kDroppedLastRef) { delete this; return 0; } return 1; } protected: ~ComRefCount() {} private: webrtc::webrtc_impl::RefCounter ref_count_{0}; }; / // 2. 是一个Pin class ComRefCount : public CaptureInputPin { public: ComRefCount() {} explicit ComRefCount(CaptureSinkFilter&& p0) : CaptureInputPin(std::forward<CaptureSinkFilter>(p0)) {} STDMETHOD_(ULONG, AddRef)() override { ref_count_.IncRef(); return 1; } STDMETHOD_(ULONG, Release)() override { const auto status = ref_count_.DecRef(); if (status == rtc::RefCountReleaseStatus::kDroppedLastRef) { delete this; return 0; } return 1; } protected: ~ComRefCount() {} private: webrtc::webrtc_impl::RefCounter ref_count_{0}; };
typedef struct _PinInfo
{
IBaseFilter *pFilter; // Filter指针
PIN_DIRECTION dir; // Pin的方向
WCHAR achName[ 128 ]; // Pin的名子
} PIN_INFO;
Filter与FilterGraph 关系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4i0NW6DK-1662190677029)(./img/filter_and_filtergraph.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kJEEYCVw-1662190677030)(./img/filter_connect.jpg)]
WebRTC中底层CapturedFilter拿到数据, 然后应用层从SinkFilter获取数据
IFilterGraph : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE AddFilter( /* [in] */ IBaseFilter *pFilter, /* [string][in] */ LPCWSTR pName) = 0; virtual HRESULT STDMETHODCALLTYPE RemoveFilter( /* [in] */ IBaseFilter *pFilter) = 0; virtual HRESULT STDMETHODCALLTYPE EnumFilters( /* [annotation][out] */ _Out_ IEnumFilters **ppEnum) = 0; virtual HRESULT STDMETHODCALLTYPE FindFilterByName( /* [string][in] */ LPCWSTR pName, /* [annotation][out] */ _Out_ IBaseFilter **ppFilter) = 0; // 两个Filter连接在一起的api // TODO@chensong 20220828 将CapturePin和 sinkPin连接起来的api // param1 : 前一个Filter的输出Pin // param2 : 后一个Filter的输入Pin // param3 : AM_MEDIA_TYPE等于DMO_MEDIA_TYPE virtual HRESULT STDMETHODCALLTYPE ConnectDirect( /* [in] */ IPin *ppinOut, /* [in] */ IPin *ppinIn, /* [annotation][unique][in] */ _In_opt_ const AM_MEDIA_TYPE *pmt) = 0; virtual HRESULT STDMETHODCALLTYPE Reconnect( /* [in] */ IPin *ppin) = 0; virtual HRESULT STDMETHODCALLTYPE Disconnect( /* [in] */ IPin *ppin) = 0; virtual HRESULT STDMETHODCALLTYPE SetDefaultSyncSource( void) = 0; };
typedef struct _AMMediaType
{
GUID majortype; // 流的主类型GUID
GUID subtype; // 流的子类型GUID
BOOL bFixedSizeSamples; // 采样算法是固定大小,音频为TRUE
BOOL bTemporalCompression; // 时域压缩
ULONG lSampleSize; // 以字节为单位的采样大小
GUID formattype; // 数据格式类型、音频为WAVEFORMATEX
IUnknown *pUnk; // 未使用
ULONG cbFormat; // 不同媒体类型格式块的大小
/* [size_is] */ BYTE *pbFormat; // 根据cbFormat决定该字段
} AM_MEDIA_TYPE;
FilterGraph调用输出Pin的Connect方法、连接输入Pin
之后调用输入Pin的ReceivConnection方法, 是否允许双方的连接
如果ReceivConnection接受连接,则两个Pin连接成功
Complete Type : 指定了具体的媒体类型 : 举例子: I420格式, rgba格式 等等
Parial Media Type : 部分类型为GUID_NULL、表示任意类型
No Media Type: 传入NULL, 表示两个Pin可以接受任意媒体类型
两个Filter交换媒体数据的机制称为transport
通常两个Filter之间通过本地内存来交换数据
有两种本地内存交换数据的方式: push和pull
push模式: 源Filter使用IMeminputPin, push数据到下游Filter
pull模式: 下游Filter向源Filter请求,通过IAsyncReader获取数据
WebRTC使用的是push模式
负责分配内存Buffer的对象称为allocator
allocator支持IMemAllocator接口
两个Pin共享同一个allocator
无论谁提供allocator,最终由输出Pin决定使用那个allocator
输出Pin还决定allocator的属性
输出Pin调用输入Pin的GetAllocatorRequirements获取buffer大小
输出Pin调用输入Pin的GetAllocator获取allocator
输入Pin调用NotifyAllocator通知输入Pin所做的选择
当流开始或停止时,输出Pin负责提交或者撤销allocator
有两种数据流: 媒体数据和控制数据
媒体数据向下游传播,控制数据向上游传播
音频、视频等都属于媒体数据
flush、流结束通知等都属于控制数据
输出Pin调用输入Pin的Receive和ReciveMultiple投递采样
如果Pin可以阻塞, ReceivecanBlock能返回S_OK
但通信情况下不应该产生阻塞
六大步骤
该接口用于报告/设置设备支持的格式和能力
CaptureFilter的CapturePin和PreviewPin支持该接口
GetNumberOfCapabilities获取Pin支持的Capa数量
GetStreamCaps获取某个具体Capability
SetFormat用于设置硬件设备的输出格式
MIDL_INTERFACE("C6E13340-30AC-11d0-A18C-00A0C9118956") IAMStreamConfig : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetFormat( /* [in] */ AM_MEDIA_TYPE *pmt) = 0; virtual HRESULT STDMETHODCALLTYPE GetFormat( /* [annotation][out] */ _Out_ AM_MEDIA_TYPE **ppmt) = 0; virtual HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities( /* [annotation][out] */ _Out_ int *piCount/*支持哪些Capabilities*/, /* [annotation][out] */ _Out_ int *piSize/*每个Capabilities的大小*/) = 0; virtual HRESULT STDMETHODCALLTYPE GetStreamCaps( /* [in] */ int iIndex/*指定获取某个Index的Capability, 从0开始*/, /* [annotation][out] */ _Out_ AM_MEDIA_TYPE **ppmt/*该方法分配且用媒体类型填充的*/, /* [annotation][out] */ _Out_ BYTE *pSCC/*调用者分配 VIDEO_STREAM_CONFIG_CAPS*/) = 0; };
该接口用于控制视频采集操作, 如枚举帧率于图像方向
GetFrameRateList用于获取采集帧率列表
MIDL_INTERFACE("6a2e0670-28e4-11d0-a18c-00a0c9118956") IAMVideoControl : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetCaps( /* [in] */ IPin *pPin, /* [annotation][out] */ _Out_ long *pCapsFlags) = 0; virtual HRESULT STDMETHODCALLTYPE SetMode( /* [in] */ IPin *pPin, /* [in] */ long Mode) = 0; virtual HRESULT STDMETHODCALLTYPE GetMode( /* [in] */ IPin *pPin, /* [annotation][out] */ _Out_ long *Mode) = 0; virtual HRESULT STDMETHODCALLTYPE GetCurrentActualFrameRate( /* [in] */ IPin *pPin, /* [annotation][out] */ _Out_ LONGLONG *ActualFrameRate) = 0; virtual HRESULT STDMETHODCALLTYPE GetMaxAvailableFrameRate( /* [in] */ IPin *pPin, /* [in] */ long iIndex, /* [in] */ SIZE Dimensions, /* [annotation][out] */ _Out_ LONGLONG *MaxAvailableFrameRate) = 0; virtual HRESULT STDMETHODCALLTYPE GetFrameRateList( /* [in] */ IPin *pPin /*查询帧率的Pin*/, /* [in] */ long iIndex /*查询帧率格式的索引值*/, /* [in] */ SIZE Dimensions /*以像素为单位图像的大小*/, /* [annotation][out] */ _Out_ long *ListSize/*用于存放帧率列表元素个数*/, /* [annotation][out] */ _Out_ LONGLONG **FrameRates/*存放帧率数组的地址指针*/) = 0; };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。