diff --git a/ext-codec/H264.cpp b/ext-codec/H264.cpp index 38c1d9bc25..bd5a7dd80e 100644 --- a/ext-codec/H264.cpp +++ b/ext-codec/H264.cpp @@ -26,6 +26,58 @@ using namespace std; using namespace toolkit; namespace mediakit { +/* Helpers to decode Exp-Golomb */ +static uint32_t h264_eg_getbit(uint8_t *base, uint32_t offset) { + return ((*(base + (offset >> 0x3))) >> (0x7 - (offset & 0x7))) & 0x1; +} + +static uint32_t h264_eg_decode(uint8_t *base, uint32_t *offset) { + uint32_t zeros = 0; + while (h264_eg_getbit(base, (*offset)++) == 0) + zeros++; + uint32_t res = 1 << zeros; + if (zeros > 0) { + int32_t i = 0; + for (i = zeros - 1; i >= 0; i--) { + res |= h264_eg_getbit(base, (*offset)++) << i; + } + } + return res - 1; +} + +// @see https://blog.csdn.net/dittychen/article/details/55509718 +int h264_frameType(uint8_t *buffer, int size) { + uint8_t nalTye = buffer[0] & 0x1F; + if (nalTye != 1 && nalTye != 5) { + return -1; + } + buffer++; + int frametype = 0; + uint32_t offset = 0; + /* i_first_mb */ + h264_eg_decode(buffer, &offset); + /* picture type */ + int frame_type = h264_eg_decode(buffer, &offset); + switch(frame_type) + { + case 0: case 5: // P + frametype = FRAME_P; + break; + case 1: case 6: // B + frametype = FRAME_B; + break; + case 3: case 8: // SP + frametype = FRAME_P; + break; + case 2: case 7: // I + frametype = FRAME_I; + break; + case 4: case 9: // SI + frametype = FRAME_I; + break; + } + return frametype; +} static bool getAVCInfo(const char *sps, size_t sps_len, int &iVideoWidth, int &iVideoHeight, float &iVideoFps) { if (sps_len < 4) { diff --git a/ext-codec/H264.h b/ext-codec/H264.h index 55b6f1ff50..7e510ade16 100644 --- a/ext-codec/H264.h +++ b/ext-codec/H264.h @@ -20,6 +20,8 @@ namespace mediakit{ void splitH264(const char *ptr, size_t len, size_t prefix, const std::function &cb); size_t prefixSize(const char *ptr, size_t len); +enum H264FrameTye { FRAME_I, FRAME_P, FRAME_B }; +int h264_frameType(uint8_t *data, int size); template class H264FrameHelper : public Parent{ @@ -72,6 +74,13 @@ class H264FrameHelper : public Parent{ // // In the case of multiple slices, first_mb_in_slice indicates the start of a frame return type >= NAL_B_P && type <= NAL_IDR && (nal_ptr[1] & 0x80); } + + bool bframe() const { + auto nal_ptr = (uint8_t *)this->data() + this->prefixSize(); + if (H264_TYPE(*nal_ptr) != NAL_B_P) + return false; + return FRAME_B == h264_frameType(nal_ptr, this->size() - this->prefixSize()); + } }; /** diff --git a/webrtc/RtcMediaSource.h b/webrtc/RtcMediaSource.h index 6e18893a0b..70ac8d218e 100644 --- a/webrtc/RtcMediaSource.h +++ b/webrtc/RtcMediaSource.h @@ -3,6 +3,8 @@ #include "Rtsp/RtspMediaSourceMuxer.h" #include "Rtsp/RtspMediaSourceImp.h" +#include "webrtc/WebRtcTransport.h" +#include "ext-codec/H264.h" namespace mediakit { class RtcMediaSourceImp : public RtspMediaSourceImp { @@ -51,7 +53,19 @@ class RtcMediaSourceMuxer : public RtspMediaSourceMuxer { _trans->delDelegate(this); } } -protected: + + bool inputFrame(const Frame::Ptr &frame) override { + // skip b-frame for webrtc + GET_CONFIG(int, dropBFrame, Rtc::kDrop264BFrame); + if (dropBFrame && frame->getCodecId() == CodecH264) { + if (FRAME_B == h264_frameType((uint8_t *)frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize())) { + DebugL << "skipBFrame " << frame->size() << " tsp:" << frame->pts() << "," << frame->dts(); + return true; + } + } + return RtspMediaSourceMuxer::inputFrame(frame); + } + protected: Track::Ptr _trans; }; diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index efc0f71b3b..cec4c9aa69 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -64,6 +64,7 @@ const string kMinBitrate = RTC_FIELD "min_bitrate"; // 数据通道设置 [AUTO-TRANSLATED:2dc48bc3] // Data channel setting const string kDataChannelEcho = RTC_FIELD "datachannel_echo"; +const string kDrop264BFrame = RTC_FIELD "drop_h264_bframe"; static onceToken token([]() { mINI::Instance()[kTimeOutSec] = 15; @@ -76,6 +77,7 @@ static onceToken token([]() { mINI::Instance()[kMaxBitrate] = 0; mINI::Instance()[kMinBitrate] = 0; + mINI::Instance()[kDrop264BFrame] = true; mINI::Instance()[kDataChannelEcho] = true; }); diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index b5cbe12da4..4c86d8b6e4 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -34,6 +34,7 @@ namespace Rtc { extern const std::string kPort; extern const std::string kTcpPort; extern const std::string kTimeOutSec; +extern const std::string kDrop264BFrame; }//namespace RTC class WebRtcInterface {