webrtc中的video rtp packet 接收組包過程
當前版本為webrtc58;
一:webrtc中,接收視訊packet的基本過程是(這裡說的的H264,vp8和vp9是一樣的過程,在解析後會判斷型別,構造RtpDepacketizer):
//接收 video rtp_packet
通過 class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> ,真正實現網路UDP資料傳送,接收;
// rtp packet 解析 為 RTPHeader + ParsedPayload -> 構造 WebRtcRTPHeader -> 構造 VCMPacket -> packet_buffer_->InsertPacket(&packet)
bool RtpReceiverImpl::IncomingRtpPacket -> int32_t RTPReceiverVideo::ParseRtpPacket -> int32_t RtpStreamReceiver::OnReceivedPayloadData
// video rtp packet -> h264 Frame
recv_video_rtp_packet -> tracker_.CopyAndFixBitstream(&packet) (h264 rtp packet 解析) -> packet_buffer_->InsertPacket(&packet) -> 獲取完整H264Frame (VideoReceiveStream::OnCompleteFrame )
,OnReceivedFrameCallback::OnReceivedFrame -> class FrameBuffer (webrtc58\src\webrtc\modules\video_coding\frame_buffer2.h) ->解碼顯示;
再看一個函式:接收端解碼前的的資料,其實這個資料更符合實際顯示資料:
VideoReceiveStream::OnEncodedImage(...)
{
}
// Called for each incoming video frame, i.e. in encoded state. E.g. used
// when
// saving the stream to a file. 'nullptr' disables the callback.
EncodedFrameObserver* pre_decode_callback
二:webrtc中的視訊快取佇列
這裡有兩個佇列:
1:video_coding::PacketBuffer;
將video rtp解析後,新增start code,然後packet_buffer_->InsertPacket(&packet) ,當判斷有完整的H264 Frame的時候,將響應:OnReceivedFrameCallback::OnReceivedFrame(std::unique_ptr<RtpFrameObject> frame) ,可以獲取完成H264 Frame;
clas PacketBuffer中的主要思路:
獲取解析後的video packet,根據 first_packet_in_frame,rtp_maker(或者根據single,或者FU-A的E==1),rtp_sqNum,每次新增排序查詢完整的Frame;
當有完整的Frame時,在查詢這個真的參考相關幀存在的完整性,將完整的Frame回調出去(放到Frame buffer 中),同時將之前的資料清空;
2: frame_buffer(frame_buffer2.h),將完整的h264 Frame排序,然後Decoder獲取解碼;
這裡說了視訊的rtp pakcet接收後的解析組包流程;
如果不用這個視訊緩衝的話,也可以向我之前的文章,通過 webrtc58\src\webrtc\modules\rtp_rtcp\source\rtp_format_h264.h 的 class RtpDepacketizerH264 : public RtpDepacketizer解析,然後自己組包;
#ifndef test_rtp_receiver_impl_h__
#define tes_trtp_receiver_impl_h__
#include "webrtc\modules\rtp_rtcp\source\rtp_receiver_impl.h"
#include "webrtc\modules\rtp_rtcp\include\rtp_receiver.h"
#include "webrtc/base/rate_limiter.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
//#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc\system_wrappers\include\clock.h"
#include "webrtc/base/array_view.h"
#include "webrtc/common_video/h264/h264_common.h"
#include "webrtc/modules/include/module_common_types.h"
//#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/base/buffer.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
#include "webrtc/base/random.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/modules/video_coding/packet_buffer.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc\modules\video_coding\h264_sps_pps_tracker.h"
#include "webrtc\modules\rtp_rtcp\include\remote_ntp_time_estimator.h"
using namespace webrtc;
constexpr int kPacketBufferStartSize = 32;
constexpr int kPacketBufferMaxSixe = 2048;
namespace webrtc {
namespace video_coding {
class CVideoRtpRecv : public OnReceivedFrameCallback
{
public:
void OnReceivedFrame(std::unique_ptr<RtpFrameObject> frame) override
{
static FILE * f = fopen("E:\\video_packet_buffer.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
}
public:
CVideoRtpRecv() :
depacketizer_(RtpDepacketizer::Create(kRtpVideoH264)),
clock_(Clock::GetRealTimeClock()),
ntp_estimator_(clock_),
last_received_timestamp_(0),
last_received_frame_time_ms_(-1),
last_received_sequence_number_(0)
{
packet_buffer_ = video_coding::PacketBuffer::Create(clock_, kPacketBufferStartSize, kPacketBufferMaxSixe, this);
}
public:
bool HaveReceivedFrame()
{
return last_received_frame_time_ms_ >= 0;
}
bool get_is_first_packet_in_frame(const RTPHeader& rtp_header)
{
bool in_order = true;
//
bool is_first_packet_in_frame = false;
{
if (HaveReceivedFrame())
{
is_first_packet_in_frame =
last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
last_received_timestamp_ != rtp_header.timestamp;
}
else
{
is_first_packet_in_frame = true;
}
}
{
if (in_order) {
if (last_received_timestamp_ != rtp_header.timestamp) {
last_received_timestamp_ = rtp_header.timestamp;
last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
}
last_received_sequence_number_ = rtp_header.sequenceNumber;
}
}
return is_first_packet_in_frame;
}
void insert_VCMPacket(uint8_t * rtp_buffer, size_t rtp_buffer_lenght)
{
RTPHeader rtp_header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
bool bIsRtcp = parser->IsRtcp(rtp_buffer, rtp_buffer_lenght);
if (bIsRtcp)
{
return;
}
bool bParser = parser->Parse(rtp_buffer, rtp_buffer_lenght, &rtp_header);
if (!bParser)
{
return;
}
//---------------------------------------------------------------
size_t nRtpHeaderLen = rtp_header.headerLength;
uint8_t * pbufPayload = (uint8_t *)(rtp_buffer + nRtpHeaderLen);
size_t nLenPayload = rtp_buffer_lenght - nRtpHeaderLen;
//
std::unique_ptr<RtpDepacketizer> depacketizer(RtpDepacketizer::Create(kRtpVideoH264));
RtpDepacketizer::ParsedPayload parsed_payload;
depacketizer->Parse(&parsed_payload, pbufPayload, nLenPayload);
//EXPECT_EQ(kVideoFrameKey, payload.frame_type);
//EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
//EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame);
//EXPECT_EQ(kH264SingleNalu, payload.type.Video.codecHeader.H264.packetization_type);
//EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
//parsed_payload.type.Video;
//const RTPVideoHeaderH264& h264 = parsed_payload.type.Video.codecHeader.H264;
//-----------------------------------------------------------------------------
#if 0
//bool RtpReceiverImpl::IncomingRtpPacket
WebRtcRTPHeader webrtc_rtp_header;
memset(&webrtc_rtp_header, 0, sizeof(webrtc_rtp_header));
webrtc_rtp_header.header = rtp_header;
//bool is_first_packet_in_frame = get_is_first_packet_in_frame(rtp_header);
if (0)
{
bool is_first_packet_in_frame = false;
{
if (HaveReceivedFrame()) {
is_first_packet_in_frame =
last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
last_received_timestamp_ != rtp_header.timestamp;
}
else {
is_first_packet_in_frame = true;
//last_received_timestamp_ = rtp_header.timestamp; //y;
}
}
}
//int32_t RTPReceiverVideo::ParseRtpPacket
webrtc_rtp_header.type.Video.codec = parsed_payload.type.Video.codec;
webrtc_rtp_header.type.Video.is_first_packet_in_frame = is_first_packet_in_frame;
webrtc_rtp_header.frameType = parsed_payload.frame_type;
webrtc_rtp_header.type = parsed_payload.type;
webrtc_rtp_header.type.Video.rotation = kVideoRotation_0;
// Retrieve the video rotation information.
if (webrtc_rtp_header.header.extension.hasVideoRotation) {
webrtc_rtp_header.type.Video.rotation =
webrtc_rtp_header.header.extension.videoRotation;
}
webrtc_rtp_header.type.Video.playout_delay = webrtc_rtp_header.header.extension.playout_delay;
//int32_t RtpStreamReceiver::OnReceivedPayloadData(
WebRtcRTPHeader rtp_header_with_ntp = webrtc_rtp_header;
rtp_header_with_ntp.ntp_time_ms = ntp_estimator_.Estimate(webrtc_rtp_header.header.timestamp);
VCMPacket packet(parsed_payload.payload, parsed_payload.payload_length, rtp_header_with_ntp);
#else
VCMPacket packet;
packet.frameType = parsed_payload.frame_type;
packet.timestamp = rtp_header.timestamp;
packet.seqNum = rtp_header.sequenceNumber;
packet.dataPtr = parsed_payload.payload;
packet.sizeBytes = parsed_payload.payload_length;
packet.markerBit = rtp_header.markerBit;
packet.codec = kVideoCodecH264;
packet.video_header = parsed_payload.type.Video;
//
packet.width = parsed_payload.type.Video.width;
packet.height = parsed_payload.type.Video.height;
packet.is_first_packet_in_frame = packet.video_header.is_first_packet_in_frame;
packet.isFirstPacket = packet.video_header.isFirstPacket;
#endif
if (packet.codec == kVideoCodecH264)
{
switch (tracker_.CopyAndFixBitstream(&packet))
{
case video_coding::H264SpsPpsTracker::kRequestKeyframe:
//keyframe_request_sender_->RequestKeyFrame();
FALLTHROUGH();
case video_coding::H264SpsPpsTracker::kDrop:
return;
case video_coding::H264SpsPpsTracker::kInsert:
break;
}
}
packet_buffer_->InsertPacket(&packet);
}
private:
rtc::scoped_refptr<video_coding::PacketBuffer> packet_buffer_;
uint32_t last_received_timestamp_;
int64_t last_received_frame_time_ms_;
uint16_t last_received_sequence_number_;
video_coding::H264SpsPpsTracker tracker_;
Clock* clock_;
RemoteNtpTimeEstimator ntp_estimator_;
int16_t last_payload_type_ = -1;
std::unique_ptr<RtpDepacketizer> depacketizer_;
};
}
}
static int file_size(char* filename)
{
FILE *fp = fopen(filename, "r");
if (!fp) return -1;
fseek(fp, 0L, SEEK_END);
int size = ftell(fp);
fclose(fp);
return size;
}
static void test_rtp_recv()
{
video_coding::CVideoRtpRecv video_rtp_pakcet_recv;
uint8_t * pRtpbuf = new uint8_t[1024 * 10];
for (int n = 0; n < 2700; n++)
{
//std::string strRtpFile = std::string("E:\\h264_rtp\\") + std::to_string(n + 1) + std::string("_h264.rtp");
std::string strRtpFile = std::string("E:\\h264_rtp_2\\") + std::to_string(n + 1) + std::string("_h264.rtp");
int nFileSize = file_size((char *)strRtpFile.c_str()); if (nFileSize <= 0) { return; }
{
FILE * f = fopen(strRtpFile.c_str(), "r+b");
fread(pRtpbuf, 1, nFileSize, f);
fclose(f);
}
//video_rtp_pakcet_recv.test(pRtpbuf, nFileSize);
video_rtp_pakcet_recv.insert_VCMPacket(pRtpbuf, nFileSize);
Sleep(5);
}
}
// webrtc58\src\webrtc\modules\video_coding\video_packet_buffer_unittest.cc(32): PacketBuffer::Create(clock_.get(), kStartSize, kMaxSize, this)) {}
// webrtc58\src\webrtc\video\rtp_stream_receiver.cc(195): packet_buffer_ = video_coding::PacketBuffer::Create(
#endif
在寫一個示例,根據 video packet 獲取完整Frame;再判斷這個完整frame的相關參考幀和獨立性;
如果可以,那麼將觸發: void OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame)
#ifndef test_rtp_receiver_Framebuffer2_impl_h__
#define test_rtp_receiver_impl_h__
#include "webrtc\modules\rtp_rtcp\source\rtp_receiver_impl.h"
#include "webrtc\modules\rtp_rtcp\include\rtp_receiver.h"
#include "webrtc/base/rate_limiter.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
//#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc\system_wrappers\include\clock.h"
#include "webrtc/base/array_view.h"
#include "webrtc/common_video/h264/h264_common.h"
#include "webrtc/modules/include/module_common_types.h"
//#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/base/buffer.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
#include "webrtc/base/random.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/modules/video_coding/packet_buffer.h"
#include "webrtc/modules/video_coding/rtp_frame_reference_finder.h"
#include "webrtc/modules/video_coding/sequence_number_util.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc\modules\video_coding\h264_sps_pps_tracker.h"
#include "webrtc\modules\rtp_rtcp\include\remote_ntp_time_estimator.h"
#include "webrtc/modules/video_coding/timing.h"
using namespace webrtc;
constexpr int kPacketBufferStartSize = 32;
constexpr int kPacketBufferMaxSixe = 2048;
namespace webrtc {
namespace video_coding {
class CVideoRtpRecv : public OnReceivedFrameCallback,
public video_coding::OnCompleteFrameCallback
{
public:
void OnReceivedFrame(std::unique_ptr<RtpFrameObject> frame) override
{
static FILE * f = fopen("E:\\video_packet_buffer.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
if (!frame->delayed_by_retransmission())
timing_->IncomingTimestamp(frame->timestamp, clock_->TimeInMilliseconds());
reference_finder_->ManageFrame(std::move(frame));
}
void /*RtpStreamReceiver::*/OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame)
{
static FILE * f = fopen("E:\\video_packet_buffer_OnCompleteFrame.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
{
rtc::CritScope lock(&last_seq_num_cs_);
video_coding::RtpFrameObject* rtp_frame =
static_cast<video_coding::RtpFrameObject*>(frame.get());
last_seq_num_for_pic_id_[rtp_frame->picture_id] = rtp_frame->last_seq_num();
}
//complete_frame_callback_->OnCompleteFrame(std::move(frame)); //another class need completeFrame; now, we not need this one;
}
public:
CVideoRtpRecv() :
depacketizer_(RtpDepacketizer::Create(kRtpVideoH264)),
clock_(Clock::GetRealTimeClock()),
ntp_estimator_(clock_),
timing_from_VideoReceiveStream_(new VCMTiming(clock_)),
timing_(timing_from_VideoReceiveStream_.get()),
last_received_timestamp_(0),
last_received_frame_time_ms_(-1),
last_received_sequence_number_(0)
{
packet_buffer_ = video_coding::PacketBuffer::Create(clock_, kPacketBufferStartSize, kPacketBufferMaxSixe, this);
reference_finder_.reset(new video_coding::RtpFrameReferenceFinder(this));
}
public:
bool HaveReceivedFrame()
{
return last_received_frame_time_ms_ >= 0;
}
bool get_is_first_packet_in_frame(const RTPHeader& rtp_header)
{
bool in_order = true;
//
bool is_first_packet_in_frame = false;
{
if (HaveReceivedFrame())
{
is_first_packet_in_frame =
last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
last_received_timestamp_ != rtp_header.timestamp;
}
else
{
is_first_packet_in_frame = true;
}
}
{
if (in_order) {
if (last_received_timestamp_ != rtp_header.timestamp) {
last_received_timestamp_ = rtp_header.timestamp;
last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
}
last_received_sequence_number_ = rtp_header.sequenceNumber;
}
}
return is_first_packet_in_frame;
}
void insert_VCMPacket(uint8_t * rtp_buffer, size_t rtp_buffer_lenght)
{
RTPHeader rtp_header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
bool bIsRtcp = parser->IsRtcp(rtp_buffer, rtp_buffer_lenght);
if (bIsRtcp)
{
return;
}
bool bParser = parser->Parse(rtp_buffer, rtp_buffer_lenght, &rtp_header);
if (!bParser)
{
return;
}
//---------------------------------------------------------------
size_t nRtpHeaderLen = rtp_header.headerLength;
uint8_t * pbufPayload = (uint8_t *)(rtp_buffer + nRtpHeaderLen);
size_t nLenPayload = rtp_buffer_lenght - nRtpHeaderLen;
//
std::unique_ptr<RtpDepacketizer> depacketizer(RtpDepacketizer::Create(kRtpVideoH264));
RtpDepacketizer::ParsedPayload parsed_payload;
depacketizer->Parse(&parsed_payload, pbufPayload, nLenPayload);
//EXPECT_EQ(kVideoFrameKey, payload.frame_type);
//EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
//EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame);
//EXPECT_EQ(kH264SingleNalu, payload.type.Video.codecHeader.H264.packetization_type);
//EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
//parsed_payload.type.Video;
//const RTPVideoHeaderH264& h264 = parsed_payload.type.Video.codecHeader.H264;
//-----------------------------------------------------------------------------
VCMPacket packet;
packet.frameType = parsed_payload.frame_type;
packet.timestamp = rtp_header.timestamp;
packet.seqNum = rtp_header.sequenceNumber;
packet.dataPtr = parsed_payload.payload;
packet.sizeBytes = parsed_payload.payload_length;
packet.markerBit = rtp_header.markerBit;
packet.codec = kVideoCodecH264;
packet.video_header = parsed_payload.type.Video;
//
packet.width = parsed_payload.type.Video.width;
packet.height = parsed_payload.type.Video.height;
packet.is_first_packet_in_frame = packet.video_header.is_first_packet_in_frame;
packet.isFirstPacket = packet.video_header.isFirstPacket;
if (packet.codec == kVideoCodecH264)
{
switch (tracker_.CopyAndFixBitstream(&packet))
{
case video_coding::H264SpsPpsTracker::kRequestKeyframe:
//keyframe_request_sender_->RequestKeyFrame();
FALLTHROUGH();
case video_coding::H264SpsPpsTracker::kDrop:
return;
case video_coding::H264SpsPpsTracker::kInsert:
break;
}
}
packet_buffer_->InsertPacket(&packet);
}
private:
rtc::scoped_refptr<video_coding::PacketBuffer> packet_buffer_;
uint32_t last_received_timestamp_;
int64_t last_received_frame_time_ms_;
uint16_t last_received_sequence_number_;
video_coding::H264SpsPpsTracker tracker_;
Clock* clock_;
//from: VideoReceiveStream; VCMTiming* timing_ use the VideoReceiveStream std::unique_ptr<VCMTiming> timing_; created, and input to rtp_stream_receiver.cc;
//the same to the webrtc code;
std::unique_ptr<VCMTiming> timing_from_VideoReceiveStream_; // Jitter buffer experiment.
RemoteNtpTimeEstimator ntp_estimator_;
int16_t last_payload_type_ = -1;
std::unique_ptr<RtpDepacketizer> depacketizer_;
// Members for the new jitter buffer experiment.
video_coding::OnCompleteFrameCallback* complete_frame_callback_;
VCMTiming* timing_;
rtc::CriticalSection last_seq_num_cs_;
std::map<uint16_t, uint16_t, DescendingSeqNumComp<uint16_t>>
last_seq_num_for_pic_id_ GUARDED_BY(last_seq_num_cs_);
std::unique_ptr<video_coding::RtpFrameReferenceFinder> reference_finder_;
};
}
}
static int file_size(char* filename)
{
FILE *fp = fopen(filename, "r");
if (!fp) return -1;
fseek(fp, 0L, SEEK_END);
int size = ftell(fp);
fclose(fp);
return size;
}
static void test_rtp_recv()
{
video_coding::CVideoRtpRecv video_rtp_pakcet_recv;
uint8_t * pRtpbuf = new uint8_t[1024 * 10];
for (int n = 0; n < 2700; n++)
{
std::string strRtpFile = std::string("E:\\h264_rtp\\") + std::to_string(n + 1) + std::string("_h264.rtp");
//std::string strRtpFile = std::string("E:\\h264_rtp_2\\") + std::to_string(n + 1) + std::string("_h264.rtp");
int nFileSize = file_size((char *)strRtpFile.c_str()); if (nFileSize <= 0) { return; }
{
FILE * f = fopen(strRtpFile.c_str(), "r+b");
fread(pRtpbuf, 1, nFileSize, f);
fclose(f);
}
//video_rtp_pakcet_recv.test(pRtpbuf, nFileSize);
video_rtp_pakcet_recv.insert_VCMPacket(pRtpbuf, nFileSize);
Sleep(5);
}
}
#endif // test_rtp_receiver_impl_h__
示例:
這裡是一個完整的示例,從video_packet -> bufferframe2;
bufferframe2主要是解決抖動問題;
通常情況,上述的第二個示例就可以了;
#ifndef test_rtp_receiver_Framebuffer2_impl_h__
#define test_rtp_receiver_Framebuffer2_impl_h__
#include "webrtc\modules\rtp_rtcp\source\rtp_receiver_impl.h"
#include "webrtc\modules\rtp_rtcp\include\rtp_receiver.h"
#include "webrtc/base/rate_limiter.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
//#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc\system_wrappers\include\clock.h"
#include "webrtc/base/array_view.h"
#include "webrtc/common_video/h264/h264_common.h"
#include "webrtc/modules/include/module_common_types.h"
//#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/base/buffer.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_format_h264.h"
#include "webrtc/base/random.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/modules/video_coding/packet_buffer.h"
#include "webrtc/modules/video_coding/rtp_frame_reference_finder.h"
#include "webrtc/modules/video_coding/sequence_number_util.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc\modules\video_coding\h264_sps_pps_tracker.h"
#include "webrtc\modules\rtp_rtcp\include\remote_ntp_time_estimator.h"
#include "webrtc/modules/video_coding/timing.h"
//
#include "webrtc/modules/video_coding/frame_buffer2.h"
#include "webrtc/modules/video_coding/jitter_estimator.h"
#include "webrtc/video/rtp_stream_receiver.h"
#include "webrtc/base/platform_thread.h"
using namespace webrtc;
constexpr int kPacketBufferStartSize = 32;
constexpr int kPacketBufferMaxSixe = 2048;
class Interface_VideoFrameToDecod
{
public:
virtual void frame_to_decode(const webrtc::VCMEncodedFrame* frame) = 0; //decoder to decode video frame in this function;
};
namespace webrtc {
namespace video_coding {
class CVideoRtpRecv : public OnReceivedFrameCallback,
public video_coding::OnCompleteFrameCallback
{
public:
void OnReceivedFrame(std::unique_ptr<RtpFrameObject> frame) override
{
static FILE * f = fopen("E:\\video_packet_buffer.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
if (!frame->delayed_by_retransmission())
timing_->IncomingTimestamp(frame->timestamp, clock_->TimeInMilliseconds());
reference_finder_->ManageFrame(std::move(frame));
}
void /*RtpStreamReceiver::*/OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame)
{
static FILE * f = fopen("E:\\video_packet_buffer_OnCompleteFrame.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
{
rtc::CritScope lock(&last_seq_num_cs_);
video_coding::RtpFrameObject* rtp_frame =
static_cast<video_coding::RtpFrameObject*>(frame.get());
last_seq_num_for_pic_id_[rtp_frame->picture_id] = rtp_frame->last_seq_num();
}
//complete_frame_callback_->OnCompleteFrame(std::move(frame)); //callback VideoReceiveStream::OnCompleteFrame;
this->VideoReceiveStream_OnCompleteFrame(std::move(frame));
}
//
void /*VideoReceiveStream::*/VideoReceiveStream_OnCompleteFrame(std::unique_ptr<video_coding::FrameObject> frame)
{
int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
if (last_continuous_pid != -1)
{
//rtp_stream_receiver_.FrameContinuous(last_continuous_pid);
}
}
public:
CVideoRtpRecv(Interface_VideoFrameToDecod * pInterface_VideoFrameToDecod) :
depacketizer_(RtpDepacketizer::Create(kRtpVideoH264)),
clock_(Clock::GetRealTimeClock()),
ntp_estimator_(clock_),
timing_from_VideoReceiveStream_(new VCMTiming(clock_)),
timing_(timing_from_VideoReceiveStream_.get()),
last_received_timestamp_(0),
last_received_frame_time_ms_(-1),
last_received_sequence_number_(0),
decode_thread_(DecodeThreadFunction, this, "DecodingThread"),
m_pInterface_VideoFrameToDecod(pInterface_VideoFrameToDecod)
{
if (m_pInterface_VideoFrameToDecod == NULL)
{
LOG(LS_ERROR) << "Interface_VideoFrameToDecod must be set, and Interface_VideoFrameToDecod must be implement;";
//exit(0);
}
packet_buffer_ = video_coding::PacketBuffer::Create(clock_, kPacketBufferStartSize, kPacketBufferMaxSixe, this);
reference_finder_.reset(new video_coding::RtpFrameReferenceFinder(this));
jitter_estimator_.reset(new VCMJitterEstimator(clock_));
frame_buffer_.reset(new video_coding::FrameBuffer(
clock_, jitter_estimator_.get(), /*timing_.get()*/timing_, /*&stats_proxy_*/NULL));
Start(); //FrameBuffre2 get Frame for decode;
}
~CVideoRtpRecv()
{
Stop();
}
public:
bool HaveReceivedFrame()
{
return last_received_frame_time_ms_ >= 0;
}
bool get_is_first_packet_in_frame(const RTPHeader& rtp_header)
{
bool in_order = true;
//
bool is_first_packet_in_frame = false;
{
if (HaveReceivedFrame())
{
is_first_packet_in_frame =
last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
last_received_timestamp_ != rtp_header.timestamp;
}
else
{
is_first_packet_in_frame = true;
}
}
{
if (in_order) {
if (last_received_timestamp_ != rtp_header.timestamp) {
last_received_timestamp_ = rtp_header.timestamp;
last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
}
last_received_sequence_number_ = rtp_header.sequenceNumber;
}
}
return is_first_packet_in_frame;
}
void insert_VCMPacket(uint8_t * rtp_buffer, size_t rtp_buffer_lenght)
{
RTPHeader rtp_header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
bool bIsRtcp = parser->IsRtcp(rtp_buffer, rtp_buffer_lenght);
if (bIsRtcp)
{
return;
}
bool bParser = parser->Parse(rtp_buffer, rtp_buffer_lenght, &rtp_header);
if (!bParser)
{
return;
}
//---------------------------------------------------------------
size_t nRtpHeaderLen = rtp_header.headerLength;
uint8_t * pbufPayload = (uint8_t *)(rtp_buffer + nRtpHeaderLen);
size_t nLenPayload = rtp_buffer_lenght - nRtpHeaderLen;
//
std::unique_ptr<RtpDepacketizer> depacketizer(RtpDepacketizer::Create(kRtpVideoH264));
RtpDepacketizer::ParsedPayload parsed_payload;
depacketizer->Parse(&parsed_payload, pbufPayload, nLenPayload);
//EXPECT_EQ(kVideoFrameKey, payload.frame_type);
//EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec);
//EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame);
//EXPECT_EQ(kH264SingleNalu, payload.type.Video.codecHeader.H264.packetization_type);
//EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type);
//parsed_payload.type.Video;
//const RTPVideoHeaderH264& h264 = parsed_payload.type.Video.codecHeader.H264;
//-----------------------------------------------------------------------------
VCMPacket packet;
packet.frameType = parsed_payload.frame_type;
packet.timestamp = rtp_header.timestamp;
packet.seqNum = rtp_header.sequenceNumber;
packet.dataPtr = parsed_payload.payload;
packet.sizeBytes = parsed_payload.payload_length;
packet.markerBit = rtp_header.markerBit;
packet.codec = kVideoCodecH264;
packet.video_header = parsed_payload.type.Video;
//
packet.width = parsed_payload.type.Video.width;
packet.height = parsed_payload.type.Video.height;
packet.is_first_packet_in_frame = packet.video_header.is_first_packet_in_frame;
packet.isFirstPacket = packet.video_header.isFirstPacket;
if (packet.codec == kVideoCodecH264)
{
switch (tracker_.CopyAndFixBitstream(&packet))
{
case video_coding::H264SpsPpsTracker::kRequestKeyframe:
//keyframe_request_sender_->RequestKeyFrame();
FALLTHROUGH();
case video_coding::H264SpsPpsTracker::kDrop:
return;
case video_coding::H264SpsPpsTracker::kInsert:
break;
}
}
packet_buffer_->InsertPacket(&packet);
}
private:
void /*VideoReceiveStream::*/Start()
{
if (decode_thread_.IsRunning())
return;
frame_buffer_->Start();
// Start the decode thread
decode_thread_.Start();
decode_thread_.SetPriority(rtc::kHighestPriority);
}
void /*VideoReceiveStream::*/Stop()
{
if (decode_thread_.IsRunning()) {
decode_thread_.Stop();
}
frame_buffer_->Stop();
}
public://private:
static bool /*VideoReceiveStream::*/DecodeThreadFunction(void* ptr)
{
//return static_cast<VideoReceiveStream*>(ptr)->Decode();
return static_cast<CVideoRtpRecv*>(ptr)->Decode();
((CVideoRtpRecv*)(ptr))->Decode();
}
bool /*VideoReceiveStream::*/Decode()
{
static const int kMaxWaitForFrameMs = 3000;
std::unique_ptr<video_coding::FrameObject> frame;
video_coding::FrameBuffer::ReturnReason res =
frame_buffer_->NextFrame(kMaxWaitForFrameMs, &frame);
if (res == video_coding::FrameBuffer::ReturnReason::kStopped)
return false;
if (frame) {
//here, wait for decode video frame, and then clear the buffer and calculate the some time; so, must to decoded , then, do next process;
//if (video_receiver_.Decode(frame.get()) == VCM_OK)
// rtp_stream_receiver_.FrameDecoded(frame->picture_id);
if (m_pInterface_VideoFrameToDecod)
{
//rtc::CritScope lock(&receive_crit_);
m_pInterface_VideoFrameToDecod->frame_to_decode(frame.get());
}
this->FrameDecoded(frame->picture_id);
}
else {
LOG(LS_WARNING) << "No decodable frame in " << kMaxWaitForFrameMs
<< " ms, requesting keyframe.";
//RequestKeyFrame();
}
return true;
}
void /*RtpStreamReceiver::*/FrameDecoded(uint16_t picture_id) {
int seq_num = -1;
{
rtc::CritScope lock(&last_seq_num_cs_);
auto seq_num_it = last_seq_num_for_pic_id_.find(picture_id);
if (seq_num_it != last_seq_num_for_pic_id_.end()) {
seq_num = seq_num_it->second;
last_seq_num_for_pic_id_.erase(last_seq_num_for_pic_id_.begin(),
++seq_num_it);
}
}
if (seq_num != -1) {
packet_buffer_->ClearTo(seq_num);
reference_finder_->ClearTo(seq_num);
}
}
private:
Interface_VideoFrameToDecod * m_pInterface_VideoFrameToDecod;
private:
rtc::scoped_refptr<video_coding::PacketBuffer> packet_buffer_;
uint32_t last_received_timestamp_;
int64_t last_received_frame_time_ms_;
uint16_t last_received_sequence_number_;
video_coding::H264SpsPpsTracker tracker_;
Clock* clock_;
//from: VideoReceiveStream; VCMTiming* timing_ use the VideoReceiveStream std::unique_ptr<VCMTiming> timing_; created, and input to rtp_stream_receiver.cc;
//the same to the webrtc code;
std::unique_ptr<VCMTiming> timing_from_VideoReceiveStream_; // Jitter buffer experiment.
RemoteNtpTimeEstimator ntp_estimator_;
int16_t last_payload_type_ = -1;
std::unique_ptr<RtpDepacketizer> depacketizer_;
// Members for the new jitter buffer experiment.
video_coding::OnCompleteFrameCallback* complete_frame_callback_;
VCMTiming* timing_;
rtc::CriticalSection last_seq_num_cs_;
std::map<uint16_t, uint16_t, DescendingSeqNumComp<uint16_t>>
last_seq_num_for_pic_id_ GUARDED_BY(last_seq_num_cs_);
std::unique_ptr<video_coding::RtpFrameReferenceFinder> reference_finder_;
//VideoReceiveStream member
rtc::PlatformThread decode_thread_;
// Members for the new jitter buffer experiment.
std::unique_ptr<VCMJitterEstimator> jitter_estimator_;
std::unique_ptr<video_coding::FrameBuffer> frame_buffer_;
//RtpStreamReceiver rtp_stream_receiver_;
};
}
}
static int file_size(char* filename)
{
FILE *fp = fopen(filename, "r");
if (!fp) return -1;
fseek(fp, 0L, SEEK_END);
int size = ftell(fp);
fclose(fp);
return size;
}
static void test_rtp_recv()
{
video_coding::CVideoRtpRecv video_rtp_pakcet_recv(NULL);
uint8_t * pRtpbuf = new uint8_t[1024 * 10];
for (int n = 0; n < 2700; n++)
{
std::string strRtpFile = std::string("E:\\h264_rtp\\") + std::to_string(n + 1) + std::string("_h264.rtp");
//std::string strRtpFile = std::string("E:\\h264_rtp_2\\") + std::to_string(n + 1) + std::string("_h264.rtp");
int nFileSize = file_size((char *)strRtpFile.c_str()); if (nFileSize <= 0) { return; }
{
FILE * f = fopen(strRtpFile.c_str(), "r+b");
fread(pRtpbuf, 1, nFileSize, f);
fclose(f);
}
//video_rtp_pakcet_recv.test(pRtpbuf, nFileSize);
video_rtp_pakcet_recv.insert_VCMPacket(pRtpbuf, nFileSize);
Sleep(5);
}
}
//----------------------------------------------framebuffer2
class CVideoRecvFramebuffer2 : public video_coding::CVideoRtpRecv, public Interface_VideoFrameToDecod
{
public:
CVideoRecvFramebuffer2() :video_coding::CVideoRtpRecv(this)
{
}
public:
virtual void frame_to_decode(const webrtc::VCMEncodedFrame* frame) override
{
// if (pre_decode_image_callback_) {
// EncodedImage encoded_image(frame->EncodedImage());
// int qp = -1;
// if (qp_parser_.GetQp(*frame, &qp)) {
// encoded_image.qp_ = qp;
// }
static FILE * f = fopen("E:\\video_packet_buffer_framebuffer2.h264", "w+b");
fwrite(frame->Buffer(), 1, frame->Length(), f);
}
};
static void test_rtp_recv_framebuffer2()
{
CVideoRecvFramebuffer2 video_rtp_pakcet_recv_framebuffer2;
uint8_t * pRtpbuf = new uint8_t[1024 * 10];
for (int n = 0; n < 2700; n++)
{
std::string strRtpFile = std::string("E:\\h264_rtp\\") + std::to_string(n + 1) + std::string("_h264.rtp");
//std::string strRtpFile = std::string("E:\\h264_rtp_2\\") + std::to_string(n + 1) + std::string("_h264.rtp");
int nFileSize = file_size((char *)strRtpFile.c_str()); if (nFileSize <= 0) { return; }
{
FILE * f = fopen(strRtpFile.c_str(), "r+b");
fread(pRtpbuf, 1, nFileSize, f);
fclose(f);
}
video_rtp_pakcet_recv_framebuffer2.insert_VCMPacket(pRtpbuf, nFileSize);
}
}
#endif // test_rtp_receiver_Framebuffer2_impl_h__
寫在最後:
重要函式1:
這有一個很重要的發現,記得之前驗證過,現在有些忘了;
1.1webrtc 單片幀???
webrtc的frame判斷,一個frame中的任何一個FU-A分包丟失都會將整個frame drop;
所以按照這個論點也沒有問題;
1.2:
packet資料到 PacketBuffer::InsertPacket(VCMPacket* packet) 中的時候,會儲存到PacketBuffer類的sequence_buffer_;
sequence_buffer_[index].frame_begin = packet->is_first_packet_in_frame; //frame的第一個packet,webrtc後面的註釋說通過s為true判斷第一個packet是謊言;(如果不是fu-a,非fu-a沒有S和E判斷;或者,如果多slice,有可能,但是webrtc應該不是)
sequence_buffer_[index].frame_end = packet->markerBit; //很直接,通過M位;fu-a可以通過E==true;
sequence_buffer_[index].seq_num = packet->seqNum;
sequence_buffer_[index].continuous = false;
sequence_buffer_[index].frame_created = false;
sequence_buffer_[index].used = true;
data_buffer_[index] = *packet;
簡單說一下sequence_buffer_,通過packet sequenceNum % sequence buffer size,將packet放到響應的位置;
sequence_buffer_就是 std::vector<ContinuityInfo> sequence_buffer_
1.3:
這個函式是在packet_buffer中查詢完整的frame;
基本邏輯:
接收到當前packet,新增到packet_buffer相應位置,通過( size_t index = seq_num % size_);
然後從當前位置的向後開始查詢frame_end;
如果找到frame_end,然後向前查詢,sequence_buffer_中的packet的sequence_num必須是連續的;直到找到時間戳不等的兩個連續的packet,那麼就認為找到first_packet了;
如果frame查詢完成,那麼 當前frame在packet_buffer索引之前的所有packet會被清理;
std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
uint16_t seq_num) {
std::vector<std::unique_ptr<RtpFrameObject>> found_frames;
for (size_t i = 0; i < size_ && PotentialNewFrame(seq_num); ++i) {
size_t index = seq_num % size_;
sequence_buffer_[index].continuous = true;
// If all packets of the frame is continuous, find the first packet of the
// frame and create an RtpFrameObject.
if (sequence_buffer_[index].frame_end) {
size_t frame_size = 0;
int max_nack_count = -1;
uint16_t start_seq_num = seq_num;
// Find the start index by searching backward until the packet with
// the |frame_begin| flag is set.
int start_index = index;
size_t tested_packets = 0;
int64_t frame_timestamp = data_buffer_[start_index].timestamp;
// Identify H.264 keyframes by means of SPS, PPS, and IDR.
bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
bool has_h264_sps = false;
bool has_h264_pps = false;
bool has_h264_idr = false;
bool is_h264_keyframe = false;
while (true) {
++tested_packets;
frame_size += data_buffer_[start_index].sizeBytes;
max_nack_count =
std::max(max_nack_count, data_buffer_[start_index].timesNacked);
sequence_buffer_[start_index].frame_created = true;
if (!is_h264 && sequence_buffer_[start_index].frame_begin)
break;
if (is_h264 && !is_h264_keyframe) {
const RTPVideoHeaderH264& header =
data_buffer_[start_index].video_header.codecHeader.H264;
for (size_t j = 0; j < header.nalus_length; ++j) {
if (header.nalus[j].type == H264::NaluType::kSps) {
has_h264_sps = true;
} else if (header.nalus[j].type == H264::NaluType::kPps) {
has_h264_pps = true;
} else if (header.nalus[j].type == H264::NaluType::kIdr) {
has_h264_idr = true;
}
}
if ((sps_pps_idr_is_h264_keyframe_ && has_h264_idr && has_h264_sps &&
has_h264_pps) ||
(!sps_pps_idr_is_h264_keyframe_ && has_h264_idr)) {
is_h264_keyframe = true;
}
}
if (tested_packets == size_)
break;
start_index = start_index > 0 ? start_index - 1 : size_ - 1;
// In the case of H264 we don't have a frame_begin bit (yes,
// |frame_begin| might be set to true but that is a lie).(為什麼這麼說?因為多slice,不合適;但是webrtc不是;!?
所以說RtpDepacketizerH264::ParseFuaNalu中的判斷不嚴謹,但是符合目前webrtc的H264結構要求;bool first_fragment = (payload_data[1] & kSBit) > 0;parsed_payload->type.Video.is_first_packet_in_frame = first_fragment; 可能是兩個人寫的程式碼;)So instead
// we traverese backwards as long as we have a previous packet and
// the timestamp of that packet is the same as this one. This may cause
// the PacketBuffer to hand out incomplete frames.
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=7106
if (is_h264 &&
(!sequence_buffer_[start_index].used ||
data_buffer_[start_index].timestamp != frame_timestamp)) {
break;
}
--start_seq_num;
}
if (is_h264) {
// Warn if this is an unsafe frame.
if (has_h264_idr && (!has_h264_sps || !has_h264_pps)) {
std::stringstream ss;
ss << "Received H.264-IDR frame "
<< "(SPS: " << has_h264_sps << ", PPS: " << has_h264_pps << "). ";
if (sps_pps_idr_is_h264_keyframe_) {
ss << "Treating as delta frame since "
"WebRTC-SpsPpsIdrIsH264Keyframe is enabled.";
} else {
ss << "Treating as key frame since "
"WebRTC-SpsPpsIdrIsH264Keyframe is disabled.";
}
RTC_LOG(LS_WARNING) << ss.str();
}
// Now that we have decided whether to treat this frame as a key frame
// or delta frame in the frame buffer, we update the field that
// determines if the RtpFrameObject is a key frame or delta frame.
const size_t first_packet_index = start_seq_num % size_;
RTC_CHECK_LT(first_packet_index, size_);
if (is_h264_keyframe) {
data_buffer_[first_packet_index].frameType = kVideoFrameKey;
} else {
data_buffer_[first_packet_index].frameType = kVideoFrameDelta;
}
// If this is not a keyframe, make sure there are no gaps in the
// packet sequence numbers up until this point.
if (!is_h264_keyframe && missing_packets_.upper_bound(start_seq_num) !=
missing_packets_.begin()) {
uint16_t stop_index = (index + 1) % size_;
while (start_index != stop_index) {
sequence_buffer_[start_index].frame_created = false;
start_index = (start_index + 1) % size_;
}
return found_frames;
}
}
missing_packets_.erase(missing_packets_.begin(),
missing_packets_.upper_bound(seq_num));
found_frames.emplace_back(
new RtpFrameObject(this, start_seq_num, seq_num, frame_size,
max_nack_count, clock_->TimeInMilliseconds()));
}
++seq_num;
}
return found_frames;
}
重要的函式2:
當packet_buffer_找到了完整frame,新增到 FrameBuffer中,還要做很多判斷:
1:如果當前frame前面的參考frame丟棄,那麼當前frame也丟棄;
2:如果framebuffer超過kMaxFramesBuffered(600),那麼新到達的frame也丟棄;
3:如果當前的frame的id是早期的,但是時間戳是新的,那麼清空framebuffer:ClearFramesAndHistory();
從當前frame開始從新解碼;
4:根據framebuffer中的最後一個frame解碼需要,可能會丟棄當前frame;
5: << "A jump in picture id was detected, clearing buffer.";
ClearFramesAndHistory();
6: RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") already inserted, dropping frame.";
7:
// Check how many dependencies that have already been fulfilled.
for (size_t i = 0; i < frame.num_references; ++i) {
FrameKey ref_key(frame.references[i], frame.spatial_layer);
auto ref_info = frames_.find(ref_key);
// Does |frame| depend on a frame earlier than the last decoded frame?
if (last_decoded_frame_it_ != frames_.end() &&
ref_key <= last_decoded_frame_it_->first) {
if (ref_info == frames_.end()) {
int64_t now_ms = clock_->TimeInMilliseconds();
if (last_log_non_decoded_ms_ + kLogNonDecodedIntervalMs < now_ms) {
RTC_LOG(LS_WARNING)
<< "Frame with (picture_id:spatial_id) (" << key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") depends on a non-decoded frame more previous than"
<< " the last decoded frame, dropping frame.";
last_log_non_decoded_ms_ = now_ms;
}
return false;
}
8:如果上述frame判斷都ok,那麼,可以將當前frame新增到framebuffer中:
info->second.frame = std::move(frame);
++num_frames_buffered_;
所以,要想獲取完整不花屏參考不相關的h264frame,那麼就要從:上述第8點獲取;
通常從: 回撥函式中獲取(可用從一開始說的decode之前獲取);
bool VideoReceiveStream::Decode() {
TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
static const int kMaxWaitForFrameMs = 3000;
static const int kMaxWaitForKeyFrameMs = 200;
int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
std::unique_ptr<video_coding::FrameObject> frame;
// TODO(philipel): Call NextFrame with |keyframe_required| argument when
// downstream project has been fixed.
video_coding::FrameBuffer::ReturnReason res =
frame_buffer_->NextFrame(wait_ms, &frame); //解碼前,從frame_buffer_獲取視訊frame;
if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
video_receiver_.DecodingStopped();
return false;
}
if (frame)
{
//解碼:。。。
}
else
{
}
//原始碼:更多細節參考webrtc原始碼:
int64_t FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) {
TRACE_EVENT0("webrtc", "FrameBuffer::InsertFrame");
RTC_DCHECK(frame);
if (stats_callback_)
stats_callback_->OnCompleteFrame(frame->is_keyframe(), frame->size(),
frame->contentType());
FrameKey key(frame->picture_id, frame->spatial_layer);
rtc::CritScope lock(&crit_);
int64_t last_continuous_picture_id =
last_continuous_frame_it_ == frames_.end()
? -1
: last_continuous_frame_it_->first.picture_id;
if (!ValidReferences(*frame)) {
RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") has invalid frame references, dropping frame.";
return last_continuous_picture_id;
}
if (num_frames_buffered_ >= kMaxFramesBuffered) {
RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") could not be inserted due to the frame "
<< "buffer being full, dropping frame.";
return last_continuous_picture_id;
}
if (last_decoded_frame_it_ != frames_.end() &&
key <= last_decoded_frame_it_->first) {
if (AheadOf(frame->timestamp, last_decoded_frame_timestamp_) &&
frame->is_keyframe()) {
// If this frame has a newer timestamp but an earlier picture id then we
// assume there has been a jump in the picture id due to some encoder
// reconfiguration or some other reason. Even though this is not according
// to spec we can still continue to decode from this frame if it is a
// keyframe.
RTC_LOG(LS_WARNING)
<< "A jump in picture id was detected, clearing buffer.";
ClearFramesAndHistory();
last_continuous_picture_id = -1;
} else {
RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") inserted after frame ("
<< last_decoded_frame_it_->first.picture_id << ":"
<< static_cast<int>(
last_decoded_frame_it_->first.spatial_layer)
<< ") was handed off for decoding, dropping frame.";
return last_continuous_picture_id;
}
}
// Test if inserting this frame would cause the order of the frames to become
// ambiguous (covering more than half the interval of 2^16). This can happen
// when the picture id make large jumps mid stream.
if (!frames_.empty() &&
key < frames_.begin()->first &&
frames_.rbegin()->first < key) {
RTC_LOG(LS_WARNING)
<< "A jump in picture id was detected, clearing buffer.";
ClearFramesAndHistory();
last_continuous_picture_id = -1;
}
auto info = frames_.insert(std::make_pair(key, FrameInfo())).first;
if (info->second.frame) {
RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< key.picture_id << ":"
<< static_cast<int>(key.spatial_layer)
<< ") already inserted, dropping frame.";
return last_continuous_picture_id;
}
if (!UpdateFrameInfoWithIncomingFrame(*frame, info))
return last_continuous_picture_id;
UpdatePlayoutDelays(*frame);
info->second.frame = std::move(frame);
++num_frames_buffered_;
if (info->second.num_missing_continuous == 0) {
info->second.continuous = true;
PropagateContinuity(info);
last_continuous_picture_id = last_continuous_frame_it_->first.picture_id;
// Since we now have new continuous frames there might be a better frame
// to return from NextFrame. Signal that thread so that it again can choose
// which frame to return.
new_continuous_frame_event_.Set();
}
return last_continuous_picture_id;
}