WebRTC Native M96 视频发送编码(OpenH264)流程以及接收视频包解码(FFmpeg)播放流程
Posted 一苇渡江694
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebRTC Native M96 视频发送编码(OpenH264)流程以及接收视频包解码(FFmpeg)播放流程相关的知识,希望对你有一定的参考价值。
H264 和 OpenH264
H.264,又称为MPEG-4第10部分,高级视频编码(英语:MPEG-4 Part 10, Advanced Video Coding,缩写为MPEG-4 AVC)是一种面向块,基于运动补偿的视频编码标准 。到2014年,它已经成为高精度视频录制、压缩和发布的最常用格式之一。第一版标准的最终草案于2003年5月完成。
H.264/AVC项目的目的是为了创建一个更佳的视频压缩标准,在更低的比特率的情况下依然能够提供良好视频质量的标准(如,一半或者更少于MPEG-2,H.263,或者MPEG-4 Part2 )。同时,还要不会太大的增加设计的复杂性。H.264的另外一个目标是提供足够的灵活性,以允许该标准能够应用于各种各样的网络和系统的各应用上,包括低和高比特率,低和高分辨率视频,广播,DVD存储,RTP / IP分组网络和ITU-T多媒体电话系统。H.264标准可以被视为由多个不同的应用框架 / 配置文件(profiles)组成的“标准系列”。
OpenH264是一个实时编码和解码视频流至H.264/MPEG-4 AVC格式的自由软件库。它采用简化BSD许可证发布
视频数据从采集到发送数据包的处理流程
视频采集线程将将采集的数据送到本地渲染和编码队列
线程:webrtc_video_capture
CaptureInputPin::Receive
CaptureSinkFilter::ProcessCapturedFrame
VideoCaptureImpl::IncomingFrame
VideoCaptureImpl::DeliverCapturedFrame(这里面有个_dataCallBack,就是看看你要把数据回调到哪,可以自己实现一个VcmCapture的,再实现一个VideoSourceImpl的类)
VcmCapturerWin::OnFrame(自己实现的类,也可以使用webrtc自带的test::VcmCapturer::OnFrame)
VideoSourceImpl::OnFrame(自己实现的类,也可以使用webrtc自带的test::TestVideoCapturer::OnFrame)
VideoBroadcaster::OnFrame
VideoStreamEncoder::OnFrame(在这里面将frame送到编码器队列encoder_queue_)
编码,视频编码器在视频帧编码结束后,发送到PacedSender队列
使用openH264进行视频编码
h264封装rtc包的细节,之后会专门去讲:fua stapa singlenalu
线程: EncoderQueue
VideoStreamEncoder::OnBitrateUpdated
VideoStreamEncoder::EncodeVideoFrame
EncoderSimulcastProxy::InitEncode
H264EncoderImpl::Encode(编码)---->CWelsH264SVCEncoder::EncodeFrame--->CWelsH264SVCEncoder::EncodeFrameInternal--->CWelsH264SVCEncoder::UpdateStatistics
VideoStreamEncoder::OnEncodedImage(编码结束)
VideoSendStreamImpl::OnEncodedImage
RtpVideoSender::OnEncodedImage
RTPSenderVideo::SendEncodedImage
RTPSenderVideo::SendVideo
打包:
RtpPacketizer::Create
RtpPacketizerH264::RtpPacketizerH264
RtpPacketizerH264::GeneratePackets
如果fragment_len > single_packet_capacity,调用RtpPacketizerH264::PacketizeFuA(例如,single_packet_capacity== 1176)
否则,调用RtpPacketizerH264::PacketizeStapA
发送到PacedSender队列:
RTPSenderVideo::LogAndSendToNetwork
RTPSender::EnqueuePackets
PacedSender::EnqueuePackets
PacingController::EnqueuePacket
PacedSender 将 RTP 包通过 MediaChannel 发送出去
线程:PacerThread
PacedSender::Process
PacingController::ProcessPackets
PacketRouter::SendPacket
ModuleRtpRtcpImpl2::TrySendPacket
RtpSenderEgress::SendPacket
RtpSenderEgress::SendPacketToNetwork
WebRtcVideoChannel::SendRtp
MediaChannel::SendRtp
MediaChannel::SendRtp() 最终将 RTP 包发送到网络的过程与音频相同
通过socket接口将数据包发送到SFU
线程:network_thread
MediaChannel::SendPacket
MediaChannel::DoSendPacket
BaseChannel::SendPacket
BaseChannel::SendPacket(bool rtcp, rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options)
SrtpTransport::SendRtpPacket
RtpTransport::SendPacket
DtlsTransport::SendPacket
P2PTransportChannel::SendPacket
ProxyConnection::Send
UDPPort::SendTo
AsyncUDPSocket::SendTo
PhysicalSocket::SendTo
PhysicalSocket::DoSendTo
::sendto
从接收视频数据包的到解码处理流程
视频接收处理从创建远端流的 VideoTrack 开始,然后为远端视频流的 VideoTrack 创建渲染器
从网络接收RTP包,识别视频的RTP
线程:network_thread
前面的调用流程跟音频一样
UDPPort::HandleIncomingPacket
UDPPort::OnReadPacket
Connection::OnReadPacket
P2PTransportChannel::OnReadPacket
DtlsTransport::OnReadPacket
RtpTransport::OnReadPacket
SrtpTransport::OnRtpPacketReceived
RtpTransport::DemuxPacket
RtpDemuxer::OnRtpPacket
BaseChannel::OnRtpPacket
WebRtcVideoChannel::OnPacketReceived
组帧并插入缓冲区
发送组装视频rtp包的时候,就有拆包,之后会详细说明。
所以,通常情况下,一个 UDP 包里是放不下一帧编码视频数据的,因而在发送端,需要分片,通过多个 RTP 包发出去,而在接收端则需要将这些 RTP 包组帧,组成一个完整的编码视频帧。
线程:worker_thread
Call::DeliverPacket
Call::DeliverRtp
RtpStreamReceiverController::OnRtpPacket
RtpDemuxer::OnRtpPacket
RtpVideoStreamReceiver2::OnRtpPacket
RtpVideoStreamReceiver2::ReceivePacket
RtpVideoStreamReceiver2::OnReceivedPayloadData
RtpVideoStreamReceiver2::OnInsertedPacket
RtpVideoStreamReceiver2::OnAssembledFrame
RtpVideoStreamReceiver2::OnCompleteFrames
VideoReceiveStream2::OnCompleteFrame
FrameBuffer::InsertFrame
视频解码
使用ffmpeg进行H264解码
线程: DecodingQueue
VideoReceiveStream2::HandleEncodedFrame
VideoReceiveStream2::DecodeAndMaybeDispatchEncodedFrame
VideoReceiver2::Decode
VCMGenericDecoder::Decode
H264DecoderImpl::Decode
VCMDecodedFrameCallback::Decoded
VideoStreamDecoder::FrameToRender
IncomingVideoStream::OnFrame(callback_->OnFrame(*frame_to_render);)
视频渲染
线程: IncomingVideoStream
IncomingVideoStream::Dequeue
VideoReceiveStream2::OnFrame
WebRtcVideoChannel::WebRtcVideoReceiveStream::OnFrame
VideoBroadcaster::OnFrame
VideoSinkImpl::OnFrame(VideoSinkImpl为自己写的类,渲染d3d)
d3d渲染代码:
if (!inited_for_raw_)
m_d3d_ = Direct3DCreate9(D3D_SDK_VERSION);
if (!m_d3d_)
return;
D3DPRESENT_PARAMETERS d3d_params = ;
d3d_params.Windowed = true;
d3d_params.SwapEffect = D3DSWAPEFFECT_COPY;
IDirect3DDevice9* d3d_device;
if (m_d3d_->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd_,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3d_params,
&d3d_device) != D3D_OK)
Destroy();
return;
m_d3d_device_ = d3d_device;
d3d_device->Release();
IDirect3DVertexBuffer9* vertex_buffer;
const int kRectVertices = 4;
if (m_d3d_device_->CreateVertexBuffer(
kRectVertices * sizeof(D3dCustomVertex), 0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_MANAGED, &vertex_buffer, nullptr) != D3D_OK)
Destroy();
return;
m_vertex_buffer_ = vertex_buffer;
vertex_buffer->Release();
m_d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
m_d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE);
Resize(video_frame.width(), video_frame.height());
inited_for_raw_ = true;
else
HRESULT hr = m_d3d_device_->TestCooperativeLevel();
if (FAILED(hr))
if(hr == D3DERR_DEVICELOST)
RTC_LOG(LS_WARNING) << "Device lost.";
else if(hr == D3DERR_DEVICENOTRESET)
Destroy();
RTC_LOG(LS_WARNING) << "Device try to reinit.";
else
RTC_LOG(LS_WARNING) << "Device driver internal error.";
return;
if (static_cast<size_t>(video_frame.width()) != width_ ||
static_cast<size_t>(video_frame.height()) != height_)
Resize(static_cast<size_t>(video_frame.width()),
static_cast<size_t>(video_frame.height()));
D3DLOCKED_RECT lock_rect;
if (m_texture_->LockRect(0, &lock_rect, nullptr, 0) != D3D_OK)
return;
ConvertFromI420(video_frame, webrtc::VideoType::kARGB, 0,
static_cast<uint8_t*>(lock_rect.pBits));
m_texture_->UnlockRect(0);
m_d3d_device_->BeginScene();
m_d3d_device_->SetFVF(D3DFVF_CUSTOMVERTEX);
m_d3d_device_->SetStreamSource(0, m_vertex_buffer_, 0,
sizeof(D3dCustomVertex));
m_d3d_device_->SetTexture(0, m_texture_);
m_d3d_device_->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_d3d_device_->EndScene();
m_d3d_device_->Present(nullptr, nullptr, wnd_, nullptr);
以上是关于WebRTC Native M96 视频发送编码(OpenH264)流程以及接收视频包解码(FFmpeg)播放流程的主要内容,如果未能解决你的问题,请参考以下文章
WebRTC Native M96 SDK接口封装--setVideoEncoderConfiguration设置本地视频的编码属性
WebRtc Native M96 远端视频接收之PacketBuffer-组帧原理分析
WebRtc Native M96 远端视频接收之PacketBuffer-组帧原理分析
WebRTC Native M96 SDK接口封装--muteLocalVideoStream开关本地视频发送