From 6bc529e55d62bc5f32956e27dfc153fb4abc4290 Mon Sep 17 00:00:00 2001 From: cqm Date: Tue, 31 Dec 2024 17:48:40 +0800 Subject: [PATCH] =?UTF-8?q?rtc=E6=BA=90=E6=94=AF=E6=8C=81=E4=B8=A2264=20b?= =?UTF-8?q?=E5=B8=A7=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ext-codec/H264.cpp | 140 ++++++++++++++++++++++++++++++++++++++++ ext-codec/H264.h | 1 + webrtc/RtcMediaSource.h | 15 ++++- 3 files changed, 154 insertions(+), 2 deletions(-) diff --git a/ext-codec/H264.cpp b/ext-codec/H264.cpp index 38c1d9bc25..e5df29f0a9 100644 --- a/ext-codec/H264.cpp +++ b/ext-codec/H264.cpp @@ -26,6 +26,146 @@ using namespace std; using namespace toolkit; namespace mediakit { +/* Helpers to decode Exp-Golomb */ +static uint32_t janus_pp_h264_eg_getbit(uint8_t *base, uint32_t offset) { + return ((*(base + (offset >> 0x3))) >> (0x7 - (offset & 0x7))) & 0x1; +} + +static uint32_t janus_pp_h264_eg_decode(uint8_t *base, uint32_t *offset) { + uint32_t zeros = 0; + while (janus_pp_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 |= janus_pp_h264_eg_getbit(base, (*offset)++) << i; + } + } + return res - 1; +} + +/* Helper to parse a SPS (only to get the video resolution) */ +static void janus_pp_h264_parse_sps(char *buffer, int *width, int *height) { + /* Let's check if it's the right profile, first */ + int index = 1; + int profile_idc = *(buffer + index); + if (profile_idc != 66) { + WarnL << "Profile is not baseline " << profile_idc; + } + /* Then let's skip 2 bytes and evaluate/skip the rest */ + index += 3; + uint32_t offset = 0; + uint8_t *base = (uint8_t *)(buffer + index); + /* Skip seq_parameter_set_id */ + janus_pp_h264_eg_decode(base, &offset); + if (profile_idc >= 100) { + /* Skip chroma_format_idc */ + janus_pp_h264_eg_decode(base, &offset); + /* Skip bit_depth_luma_minus8 */ + janus_pp_h264_eg_decode(base, &offset); + /* Skip bit_depth_chroma_minus8 */ + janus_pp_h264_eg_decode(base, &offset); + /* Skip qpprime_y_zero_transform_bypass_flag */ + janus_pp_h264_eg_getbit(base, offset++); + /* Skip seq_scaling_matrix_present_flag */ + janus_pp_h264_eg_getbit(base, offset++); + } + /* Skip log2_max_frame_num_minus4 */ + janus_pp_h264_eg_decode(base, &offset); + /* Evaluate pic_order_cnt_type */ + int pic_order_cnt_type = janus_pp_h264_eg_decode(base, &offset); + if (pic_order_cnt_type == 0) { + /* Skip log2_max_pic_order_cnt_lsb_minus4 */ + janus_pp_h264_eg_decode(base, &offset); + } else if (pic_order_cnt_type == 1) { + /* Skip delta_pic_order_always_zero_flag, offset_for_non_ref_pic, + * offset_for_top_to_bottom_field and num_ref_frames_in_pic_order_cnt_cycle */ + janus_pp_h264_eg_getbit(base, offset++); + janus_pp_h264_eg_decode(base, &offset); + janus_pp_h264_eg_decode(base, &offset); + int num_ref_frames_in_pic_order_cnt_cycle = janus_pp_h264_eg_decode(base, &offset); + int i = 0; + for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) { + janus_pp_h264_eg_decode(base, &offset); + } + } + /* Skip max_num_ref_frames and gaps_in_frame_num_value_allowed_flag */ + janus_pp_h264_eg_decode(base, &offset); + janus_pp_h264_eg_getbit(base, offset++); + /* We need the following three values */ + int pic_width_in_mbs_minus1 = janus_pp_h264_eg_decode(base, &offset); + int pic_height_in_map_units_minus1 = janus_pp_h264_eg_decode(base, &offset); + int frame_mbs_only_flag = janus_pp_h264_eg_getbit(base, offset++); + if (!frame_mbs_only_flag) { + /* Skip mb_adaptive_frame_field_flag */ + janus_pp_h264_eg_getbit(base, offset++); + } + /* Skip direct_8x8_inference_flag */ + janus_pp_h264_eg_getbit(base, offset++); + /* We need the following value to evaluate offsets, if any */ + int frame_cropping_flag = janus_pp_h264_eg_getbit(base, offset++); + int frame_crop_left_offset = 0, frame_crop_right_offset = 0, frame_crop_top_offset = 0, frame_crop_bottom_offset = 0; + if (frame_cropping_flag) { + frame_crop_left_offset = janus_pp_h264_eg_decode(base, &offset); + frame_crop_right_offset = janus_pp_h264_eg_decode(base, &offset); + frame_crop_top_offset = janus_pp_h264_eg_decode(base, &offset); + frame_crop_bottom_offset = janus_pp_h264_eg_decode(base, &offset); + } + /* Skip vui_parameters_present_flag */ + janus_pp_h264_eg_getbit(base, offset++); + + /* We skipped what we didn't care about and got what we wanted, compute width/height */ + if (width) + *width = ((pic_width_in_mbs_minus1 + 1) * 16) - frame_crop_left_offset * 2 - frame_crop_right_offset * 2; + if (height) + *height = ((2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2); +} + +enum SrsAvcSliceType { + SrsAvcSliceTypeP = 0, + SrsAvcSliceTypeB = 1, + SrsAvcSliceTypeI = 2, + SrsAvcSliceTypeSP = 3, + SrsAvcSliceTypeSI = 4, + SrsAvcSliceTypeP1 = 5, + SrsAvcSliceTypeB1 = 6, + SrsAvcSliceTypeI1 = 7, + SrsAvcSliceTypeSP1 = 8, + SrsAvcSliceTypeSI1 = 9, +}; + +bool h264_is_bframe(uint8_t *buffer, int size) { + uint8_t nalTye = buffer[0] & 0x1F; + if (nalTye = 5 || nalTye == 1) { + return false; + } + buffer++; + uint32_t offset = 0; + /* i_first_mb */ + janus_pp_h264_eg_decode(buffer, &offset); + /* picture type */ + int frame_type = janus_pp_h264_eg_decode(buffer, &offset); + switch(frame_type) + { + case 0: case 5: // P + //nal->Frametype = FRAME_P; + break; + case 1: case 6: // B + return true; + break; + case 3: case 8: // SP + //nal->Frametype = FRAME_P; + break; + case 2: case 7: // I + //nal->Frametype = FRAME_I; + break; + case 4: case 9: // SI + //nal->Frametype = FRAME_I; + break; + } + return false; +} 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..d4dba86742 100644 --- a/ext-codec/H264.h +++ b/ext-codec/H264.h @@ -20,6 +20,7 @@ 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); +bool h264_is_bframe(uint8_t *buffer, int size); template class H264FrameHelper : public Parent{ diff --git a/webrtc/RtcMediaSource.h b/webrtc/RtcMediaSource.h index 6e18893a0b..4dc874d856 100644 --- a/webrtc/RtcMediaSource.h +++ b/webrtc/RtcMediaSource.h @@ -4,7 +4,7 @@ #include "Rtsp/RtspMediaSourceMuxer.h" #include "Rtsp/RtspMediaSourceImp.h" namespace mediakit { - +extern bool h264_is_bframe(uint8_t *buffer, int size); class RtcMediaSourceImp : public RtspMediaSourceImp { public: using Ptr = std::shared_ptr; @@ -51,7 +51,18 @@ class RtcMediaSourceMuxer : public RtspMediaSourceMuxer { _trans->delDelegate(this); } } -protected: + + bool inputFrame(const Frame::Ptr &frame) override { + // skip b-frame for webrtc + if (frame->getCodecId() == CodecH264) { + if (h264_is_bframe((uint8_t *)frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize())) { + DebugL << "skipFrame " << frame->size() << " tsp:" << frame->pts() << "," << frame->dts(); + return true; + } + } + return RtspMediaSourceMuxer::inputFrame(frame); + } + protected: Track::Ptr _trans; };