2018-10-25 10:00:17 +08:00
/*
2023-12-09 16:23:51 +08:00
* Copyright ( c ) 2016 - present The ZLMediaKit project authors . All Rights Reserved .
2018-10-25 10:00:17 +08:00
*
2023-12-09 16:23:51 +08:00
* This file is part of ZLMediaKit ( https : //github.com/ZLMediaKit/ZLMediaKit).
2018-10-25 10:00:17 +08:00
*
2023-12-09 16:23:51 +08:00
* Use of this source code is governed by MIT - like license that can be found in the
2020-04-04 20:30:09 +08:00
* LICENSE file in the root of the source tree . All contributing project authors
* may be found in the AUTHORS file in the root of the source tree .
2018-10-25 10:00:17 +08:00
*/
2018-10-21 21:21:14 +08:00
2019-06-28 17:37:11 +08:00
# include "H264Rtp.h"
2022-11-29 11:07:13 +08:00
# include "Common/config.h"
2018-10-21 21:21:14 +08:00
2018-10-24 17:17:55 +08:00
namespace mediakit {
2018-10-21 22:24:24 +08:00
2021-02-07 18:29:48 +08:00
# pragma pack(push, 1)
class FuFlags {
public :
# if __BYTE_ORDER == __BIG_ENDIAN
unsigned start_bit : 1 ;
unsigned end_bit : 1 ;
unsigned reserved : 1 ;
unsigned nal_type : 5 ;
# else
unsigned nal_type : 5 ;
unsigned reserved : 1 ;
unsigned end_bit : 1 ;
unsigned start_bit : 1 ;
# endif
2023-07-29 13:07:22 +08:00
} ;
2021-02-07 18:29:48 +08:00
# pragma pack(pop)
2018-10-25 23:24:23 +08:00
2018-10-21 22:24:24 +08:00
H264RtpDecoder : : H264RtpDecoder ( ) {
2021-02-07 18:29:48 +08:00
_frame = obtainFrame ( ) ;
2018-10-21 22:24:24 +08:00
}
2021-02-05 11:51:16 +08:00
H264Frame : : Ptr H264RtpDecoder : : obtainFrame ( ) {
auto frame = FrameImp : : create < H264Frame > ( ) ;
2020-01-14 10:04:24 +08:00
frame - > _prefix_size = 4 ;
2018-10-21 22:24:24 +08:00
return frame ;
}
2018-10-23 18:39:17 +08:00
bool H264RtpDecoder : : inputRtp ( const RtpPacket : : Ptr & rtp , bool key_pos ) {
2021-07-29 16:22:43 +08:00
auto seq = rtp - > getSeq ( ) ;
2023-11-07 19:34:40 +08:00
auto last_is_gop = _is_gop ;
_is_gop = decodeRtp ( rtp ) ;
if ( ! _gop_dropped & & seq ! = ( uint16_t ) ( _last_seq + 1 ) & & _last_seq ) {
2021-07-29 16:22:43 +08:00
_gop_dropped = true ;
WarnL < < " start drop h264 gop, last seq: " < < _last_seq < < " , rtp: \r \n " < < rtp - > dumpString ( ) ;
}
_last_seq = seq ;
2024-09-19 14:53:50 +08:00
// 确保有sps rtp的时候, gop从sps开始; 否则从关键帧开始 [AUTO-TRANSLATED:115ae07c]
// cpp
// Ensure that when there is sps rtp, the gop starts from sps; otherwise, it starts from the key frame
2023-11-07 19:34:40 +08:00
return _is_gop & & ! last_is_gop ;
2018-10-21 21:21:14 +08:00
}
2021-02-07 18:29:48 +08:00
/*
RTF3984 5.2 节 Common Structure of the RTP Payload Format
Table 1. Summary of NAL unit types and their payload structures
Type Packet Type name Section
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 undefined -
1 - 23 NAL unit Single NAL unit packet per H .264 5.6
24 STAP - A Single - time aggregation packet 5.7 .1
25 STAP - B Single - time aggregation packet 5.7 .1
26 MTAP16 Multi - time aggregation packet 5.7 .2
27 MTAP24 Multi - time aggregation packet 5.7 .2
28 FU - A Fragmentation unit 5.8
29 FU - B Fragmentation unit 5.8
30 - 31 undefined -
2024-09-19 14:53:50 +08:00
/*
RTF3984 Section 5.2 Common Structure of the RTP Payload Format
Table 1. Summary of NAL unit types and their payload structures
Type Packet Type name Section
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 undefined -
1 - 23 NAL unit Single NAL unit packet per H .264 5.6
24 STAP - A Single - time aggregation packet 5.7 .1
25 STAP - B Single - time aggregation packet 5.7 .1
26 MTAP16 Multi - time aggregation packet 5.7 .2
27 MTAP24 Multi - time aggregation packet 5.7 .2
28 FU - A Fragmentation unit 5.8
29 FU - B Fragmentation unit 5.8
30 - 31 undefined -
* [ AUTO - TRANSLATED : 57545317 ]
2021-02-07 18:29:48 +08:00
*/
2022-08-08 17:13:39 +08:00
bool H264RtpDecoder : : singleFrame ( const RtpPacket : : Ptr & rtp , const uint8_t * ptr , ssize_t size , uint64_t stamp ) {
2021-07-29 16:22:43 +08:00
_frame - > _buffer . assign ( " \x00 \x00 \x00 \x01 " , 4 ) ;
_frame - > _buffer . append ( ( char * ) ptr , size ) ;
_frame - > _pts = stamp ;
2023-11-07 19:34:40 +08:00
auto key = _frame - > keyFrame ( ) | | _frame - > configFrame ( ) ;
2021-07-29 16:22:43 +08:00
outputFrame ( rtp , _frame ) ;
return key ;
}
2018-10-21 21:21:14 +08:00
2022-08-08 17:13:39 +08:00
bool H264RtpDecoder : : unpackStapA ( const RtpPacket : : Ptr & rtp , const uint8_t * ptr , ssize_t size , uint64_t stamp ) {
2024-09-19 14:53:50 +08:00
// STAP-A 单一时间的组合包 [AUTO-TRANSLATED:cfa62307]
// STAP-A single-time aggregation packet
2021-07-29 16:22:43 +08:00
auto have_key_frame = false ;
auto end = ptr + size ;
while ( ptr + 2 < end ) {
uint16_t len = ( ptr [ 0 ] < < 8 ) | ptr [ 1 ] ;
if ( ! len | | ptr + len > end ) {
WarnL < < " invalid rtp data size: " < < len < < " ,rtp: \r \n " < < rtp - > dumpString ( ) ;
_gop_dropped = true ;
break ;
}
ptr + = 2 ;
if ( singleFrame ( rtp , ptr , len , stamp ) ) {
have_key_frame = true ;
}
ptr + = len ;
}
return have_key_frame ;
}
2022-08-08 17:13:39 +08:00
bool H264RtpDecoder : : mergeFu ( const RtpPacket : : Ptr & rtp , const uint8_t * ptr , ssize_t size , uint64_t stamp , uint16_t seq ) {
2021-07-29 16:22:43 +08:00
auto nal_suffix = * ptr & ( ~ 0x1F ) ;
FuFlags * fu = ( FuFlags * ) ( ptr + 1 ) ;
if ( fu - > start_bit ) {
2024-09-19 14:53:50 +08:00
// 该帧的第一个rtp包 [AUTO-TRANSLATED:a9581a23]
// The first rtp packet of this frame
2021-02-07 18:29:48 +08:00
_frame - > _buffer . assign ( " \x00 \x00 \x00 \x01 " , 4 ) ;
2021-07-29 16:22:43 +08:00
_frame - > _buffer . push_back ( nal_suffix | fu - > nal_type ) ;
2021-02-07 18:29:48 +08:00
_frame - > _pts = stamp ;
2021-07-29 16:22:43 +08:00
_fu_dropped = false ;
2018-10-21 21:21:14 +08:00
}
2021-07-29 16:22:43 +08:00
if ( _fu_dropped ) {
2024-09-19 14:53:50 +08:00
// 该帧不完整 [AUTO-TRANSLATED:6bd7eca7]
// This frame is incomplete
2021-07-29 16:22:43 +08:00
return false ;
}
2018-10-21 21:21:14 +08:00
2021-07-29 16:22:43 +08:00
if ( ! fu - > start_bit & & seq ! = ( uint16_t ) ( _last_seq + 1 ) ) {
2024-09-19 14:53:50 +08:00
// 中间的或末尾的rtp包, 其seq必须连续, 否则说明rtp丢包, 那么该帧不完整, 必须得丢弃 [AUTO-TRANSLATED:6953b332]
// The middle or end rtp packet, its seq must be continuous, otherwise it indicates that the rtp packet is lost, then the frame is incomplete and must be discarded
2021-07-29 16:22:43 +08:00
_fu_dropped = true ;
_frame - > _buffer . clear ( ) ;
return false ;
}
2019-01-17 18:26:28 +08:00
2024-09-19 14:53:50 +08:00
// 后面追加数据 [AUTO-TRANSLATED:248516e9]
// Append data
2021-07-29 16:22:43 +08:00
_frame - > _buffer . append ( ( char * ) ptr + 2 , size - 2 ) ;
2019-08-01 14:39:09 +08:00
2021-07-29 16:22:43 +08:00
if ( ! fu - > end_bit ) {
2024-09-19 14:53:50 +08:00
// 非末尾包 [AUTO-TRANSLATED:2e43ac3c]
// Not the end packet
2023-11-07 19:34:40 +08:00
return fu - > start_bit ? ( _frame - > keyFrame ( ) | | _frame - > configFrame ( ) ) : false ;
2021-07-29 16:22:43 +08:00
}
2019-08-01 14:39:09 +08:00
2024-09-19 14:53:50 +08:00
// 确保下一次fu必须收到第一个包 [AUTO-TRANSLATED:491d81ec]
// Ensure that the next fu must receive the first packet
2021-07-29 16:22:43 +08:00
_fu_dropped = true ;
2024-09-19 14:53:50 +08:00
// 该帧最后一个rtp包,输出frame [AUTO-TRANSLATED:a648aaa5]
// The last rtp packet of this frame, output frame
2021-07-29 16:22:43 +08:00
outputFrame ( rtp , _frame ) ;
return false ;
}
bool H264RtpDecoder : : decodeRtp ( const RtpPacket : : Ptr & rtp ) {
2022-05-28 10:34:54 +08:00
auto payload_size = rtp - > getPayloadSize ( ) ;
if ( payload_size < = 0 ) {
2024-09-19 14:53:50 +08:00
// 无实际负载 [AUTO-TRANSLATED:305af48f]
// No actual payload
2022-05-28 10:34:54 +08:00
return false ;
}
2021-07-29 16:22:43 +08:00
auto frame = rtp - > getPayload ( ) ;
auto stamp = rtp - > getStampMS ( ) ;
auto seq = rtp - > getSeq ( ) ;
int nal = H264_TYPE ( frame [ 0 ] ) ;
switch ( nal ) {
case 24 :
// 24 STAP-A Single-time aggregation packet 5.7.1
2022-05-28 10:34:54 +08:00
return unpackStapA ( rtp , frame + 1 , payload_size - 1 , stamp ) ;
2021-07-29 16:22:43 +08:00
case 28 :
// 28 FU-A Fragmentation unit
2022-05-28 10:34:54 +08:00
return mergeFu ( rtp , frame , payload_size , stamp , seq ) ;
2019-01-17 18:26:28 +08:00
2020-07-26 19:56:39 +08:00
default : {
2021-07-29 16:22:43 +08:00
if ( nal < 24 ) {
//Single NAL Unit Packets
2022-05-28 10:34:54 +08:00
return singleFrame ( rtp , frame , payload_size , stamp ) ;
2021-07-29 16:22:43 +08:00
}
_gop_dropped = true ;
WarnL < < " 不支持该类型的264 RTP包, nal type: " < < nal < < " , rtp: \r \n " < < rtp - > dumpString ( ) ;
2019-01-17 18:26:28 +08:00
return false ;
2018-10-21 21:21:14 +08:00
}
}
}
2021-07-29 16:22:43 +08:00
void H264RtpDecoder : : outputFrame ( const RtpPacket : : Ptr & rtp , const H264Frame : : Ptr & frame ) {
2021-08-23 21:48:30 +08:00
if ( frame - > dropAble ( ) ) {
2024-09-19 14:53:50 +08:00
// 不参与dts生成 [AUTO-TRANSLATED:dff3b747]
// Not involved in dts generation
2021-08-23 21:48:30 +08:00
frame - > _dts = frame - > _pts ;
} else {
2024-09-19 14:53:50 +08:00
// rtsp没有dts, 那么根据pts排序算法生成dts [AUTO-TRANSLATED:f37c17f3]
// Rtsp does not have dts, so dts is generated according to the pts sorting algorithm
2021-08-23 21:48:30 +08:00
_dts_generator . getDts ( frame - > _pts , frame - > _dts ) ;
}
2021-07-29 16:22:43 +08:00
if ( frame - > keyFrame ( ) & & _gop_dropped ) {
_gop_dropped = false ;
InfoL < < " new gop received, rtp: \r \n " < < rtp - > dumpString ( ) ;
}
2024-08-14 20:11:24 +08:00
if ( ! _gop_dropped | | frame - > configFrame ( ) ) {
2021-07-29 16:22:43 +08:00
RtpCodec : : inputFrame ( frame ) ;
}
2021-02-07 18:29:48 +08:00
_frame = obtainFrame ( ) ;
2018-10-21 21:21:14 +08:00
}
2018-10-21 21:45:44 +08:00
////////////////////////////////////////////////////////////////////////
2022-08-08 17:13:39 +08:00
void H264RtpEncoder : : insertConfigFrame ( uint64_t pts ) {
2021-04-15 19:46:45 +08:00
if ( ! _sps | | ! _pps ) {
2021-04-15 00:15:41 +08:00
return ;
}
2024-09-19 14:53:50 +08:00
// gop缓存从sps开始, sps、pps后面还有时间戳相同的关键帧, 所以mark bit为false [AUTO-TRANSLATED:e8dcff77]
// The gop cache starts from sps, sps, pps and then there are key frames with the same timestamp, so the mark bit is false
2021-04-15 19:46:45 +08:00
packRtp ( _sps - > data ( ) + _sps - > prefixSize ( ) , _sps - > size ( ) - _sps - > prefixSize ( ) , pts , false , true ) ;
packRtp ( _pps - > data ( ) + _pps - > prefixSize ( ) , _pps - > size ( ) - _pps - > prefixSize ( ) , pts , false , false ) ;
2021-04-15 19:39:24 +08:00
}
2021-04-15 00:15:41 +08:00
2022-08-08 17:13:39 +08:00
void H264RtpEncoder : : packRtp ( const char * ptr , size_t len , uint64_t pts , bool is_mark , bool gop_pos ) {
2023-12-09 16:23:51 +08:00
if ( len + 3 < = getRtpInfo ( ) . getMaxSize ( ) ) {
2024-09-19 14:53:50 +08:00
// 采用STAP-A/Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:1a719984]
// Use STAP-A/Single NAL unit packet per H.264 mode
2023-06-26 10:04:16 +08:00
packRtpSmallFrame ( ptr , len , pts , is_mark , gop_pos ) ;
2021-04-15 19:39:24 +08:00
} else {
2024-09-19 14:53:50 +08:00
// STAP-A模式打包会大于MTU,所以采用FU-A模式 [AUTO-TRANSLATED:f3923abc]
// STAP-A mode packaging will be larger than MTU, so FU-A mode is used
2021-04-15 19:39:24 +08:00
packRtpFu ( ptr , len , pts , is_mark , gop_pos ) ;
2021-04-15 00:15:41 +08:00
}
2021-04-15 19:39:24 +08:00
}
2021-04-15 00:15:41 +08:00
2022-08-08 17:13:39 +08:00
void H264RtpEncoder : : packRtpFu ( const char * ptr , size_t len , uint64_t pts , bool is_mark , bool gop_pos ) {
2023-12-09 16:23:51 +08:00
auto packet_size = getRtpInfo ( ) . getMaxSize ( ) - 2 ;
2021-04-28 16:07:01 +08:00
if ( len < = packet_size + 1 ) {
2024-09-19 14:53:50 +08:00
// 小于FU-A打包最小字节长度要求, 采用STAP-A/Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:b83bb4d1]
// Less than the minimum byte length requirement for FU-A packaging, use STAP-A/Single NAL unit packet per H.264 mode
2023-06-26 10:04:16 +08:00
packRtpSmallFrame ( ptr , len , pts , is_mark , gop_pos ) ;
2021-04-15 13:54:03 +08:00
return ;
}
2021-02-07 18:29:48 +08:00
2024-09-19 14:53:50 +08:00
// 末尾5bit为nalu type, 固定为28(FU-A) [AUTO-TRANSLATED:6293f1a9]
// The last 5 bits are the nalu type, fixed to 28 (FU-A)
2021-02-07 18:29:48 +08:00
auto fu_char_0 = ( ptr [ 0 ] & ( ~ 0x1F ) ) | 28 ;
2021-04-15 19:39:24 +08:00
auto fu_char_1 = H264_TYPE ( ptr [ 0 ] ) ;
2021-02-07 18:29:48 +08:00
FuFlags * fu_flags = ( FuFlags * ) ( & fu_char_1 ) ;
fu_flags - > start_bit = 1 ;
2018-10-21 21:45:44 +08:00
2021-04-15 19:39:24 +08:00
size_t offset = 1 ;
while ( ! fu_flags - > end_bit ) {
if ( ! fu_flags - > start_bit & & len < = offset + packet_size ) {
//FU-A end
packet_size = len - offset ;
fu_flags - > end_bit = 1 ;
2018-10-21 21:45:44 +08:00
}
2021-04-15 19:39:24 +08:00
2024-09-19 14:53:50 +08:00
// 传入nullptr先不做payload的内存拷贝 [AUTO-TRANSLATED:1858cf77]
// Pass in nullptr first, do not copy the payload memory
2023-12-09 16:23:51 +08:00
auto rtp = getRtpInfo ( ) . makeRtp ( TrackVideo , nullptr , packet_size + 2 , fu_flags - > end_bit & & is_mark , pts ) ;
2024-09-19 14:53:50 +08:00
// rtp payload 负载部分 [AUTO-TRANSLATED:aecf73cc]
// rtp payload load part
2021-04-15 00:15:41 +08:00
uint8_t * payload = rtp - > getPayload ( ) ;
2024-09-19 14:53:50 +08:00
// FU-A 第1个字节 [AUTO-TRANSLATED:b5558495]
// FU-A first byte
2021-04-15 19:39:24 +08:00
payload [ 0 ] = fu_char_0 ;
2024-09-19 14:53:50 +08:00
// FU-A 第2个字节 [AUTO-TRANSLATED:6b4540bb]
// FU-A second byte
2021-04-15 19:39:24 +08:00
payload [ 1 ] = fu_char_1 ;
2024-09-19 14:53:50 +08:00
// H264 数据 [AUTO-TRANSLATED:79204239]
// H264 data
2021-04-15 19:39:24 +08:00
memcpy ( payload + 2 , ( uint8_t * ) ptr + offset , packet_size ) ;
2024-09-19 14:53:50 +08:00
// 输入到rtp环形缓存 [AUTO-TRANSLATED:5208ef90]
// Input to the rtp ring buffer
2021-04-15 19:39:24 +08:00
RtpCodec : : inputRtp ( rtp , gop_pos ) ;
offset + = packet_size ;
fu_flags - > start_bit = 0 ;
2018-10-21 21:45:44 +08:00
}
2021-04-15 19:39:24 +08:00
}
2021-04-15 13:54:03 +08:00
2023-06-26 10:04:16 +08:00
void H264RtpEncoder : : packRtpSmallFrame ( const char * data , size_t len , uint64_t pts , bool is_mark , bool gop_pos ) {
GET_CONFIG ( bool , h264_stap_a , Rtp : : kH264StapA ) ;
if ( h264_stap_a ) {
packRtpStapA ( data , len , pts , is_mark , gop_pos ) ;
} else {
packRtpSingleNalu ( data , len , pts , is_mark , gop_pos ) ;
}
}
2022-08-08 17:13:39 +08:00
void H264RtpEncoder : : packRtpStapA ( const char * ptr , size_t len , uint64_t pts , bool is_mark , bool gop_pos ) {
2024-09-19 14:53:50 +08:00
// 如果帧长度不超过mtu,为了兼容性 webrtc, 采用STAP-A模式打包 [AUTO-TRANSLATED:a091199c]
// If the frame length does not exceed mtu, for compatibility with webrtc, use STAP-A mode packaging
2023-12-09 16:23:51 +08:00
auto rtp = getRtpInfo ( ) . makeRtp ( TrackVideo , nullptr , len + 3 , is_mark , pts ) ;
2021-04-15 19:39:24 +08:00
uint8_t * payload = rtp - > getPayload ( ) ;
//STAP-A
payload [ 0 ] = ( ptr [ 0 ] & ( ~ 0x1F ) ) | 24 ;
payload [ 1 ] = ( len > > 8 ) & 0xFF ;
payload [ 2 ] = len & 0xff ;
memcpy ( payload + 3 , ( uint8_t * ) ptr , len ) ;
RtpCodec : : inputRtp ( rtp , gop_pos ) ;
2018-10-21 21:45:44 +08:00
}
2023-06-26 10:04:16 +08:00
void H264RtpEncoder : : packRtpSingleNalu ( const char * data , size_t len , uint64_t pts , bool is_mark , bool gop_pos ) {
2024-09-19 14:53:50 +08:00
// Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:9332a8e4]
// Single NAL unit packet per H.264 mode
2023-12-09 16:23:51 +08:00
RtpCodec : : inputRtp ( getRtpInfo ( ) . makeRtp ( TrackVideo , data , len , is_mark , pts ) , gop_pos ) ;
2023-06-26 10:04:16 +08:00
}
2021-09-27 13:12:53 +08:00
bool H264RtpEncoder : : inputFrame ( const Frame : : Ptr & frame ) {
2021-04-15 19:39:24 +08:00
auto ptr = frame - > data ( ) + frame - > prefixSize ( ) ;
switch ( H264_TYPE ( ptr [ 0 ] ) ) {
case H264Frame : : NAL_SPS : {
2021-04-15 19:46:45 +08:00
_sps = Frame : : getCacheAbleFrame ( frame ) ;
2021-09-27 13:12:53 +08:00
return true ;
2021-04-15 19:39:24 +08:00
}
case H264Frame : : NAL_PPS : {
2021-04-15 19:46:45 +08:00
_pps = Frame : : getCacheAbleFrame ( frame ) ;
2021-09-27 13:12:53 +08:00
return true ;
2021-04-15 19:39:24 +08:00
}
default : break ;
}
2022-10-19 14:55:39 +08:00
GET_CONFIG ( int , lowLatency , Rtp : : kLowLatency ) ;
2022-10-19 14:20:53 +08:00
if ( lowLatency ) { // 低延迟模式
if ( _last_frame ) {
flush ( ) ;
}
inputFrame_l ( frame , true ) ;
} else {
if ( _last_frame ) {
2024-09-19 14:53:50 +08:00
// 如果时间戳发生了变化, 那么markbit才置true [AUTO-TRANSLATED:19b68429]
// If the timestamp changes, then the markbit is set to true
2022-10-19 14:20:53 +08:00
inputFrame_l ( _last_frame , _last_frame - > pts ( ) ! = frame - > pts ( ) ) ;
}
_last_frame = Frame : : getCacheAbleFrame ( frame ) ;
2021-04-15 19:39:24 +08:00
}
2021-09-27 13:12:53 +08:00
return true ;
2021-04-15 19:39:24 +08:00
}
2022-10-16 19:49:56 +08:00
void H264RtpEncoder : : flush ( ) {
if ( _last_frame ) {
2024-09-19 14:53:50 +08:00
// 如果时间戳发生了变化, 那么markbit才置true [AUTO-TRANSLATED:6b1d0fe0]
// If the timestamp changes, then the markbit is set to true
2022-10-16 19:49:56 +08:00
inputFrame_l ( _last_frame , true ) ;
_last_frame = nullptr ;
}
}
2021-09-27 13:12:53 +08:00
bool H264RtpEncoder : : inputFrame_l ( const Frame : : Ptr & frame , bool is_mark ) {
2021-04-15 19:39:24 +08:00
if ( frame - > keyFrame ( ) ) {
2024-09-19 14:53:50 +08:00
// 保证每一个关键帧前都有SPS与PPS [AUTO-TRANSLATED:9d1a9d5e]
// Ensure that there are SPS and PPS before each key frame
2021-04-15 19:39:24 +08:00
insertConfigFrame ( frame - > pts ( ) ) ;
}
packRtp ( frame - > data ( ) + frame - > prefixSize ( ) , frame - > size ( ) - frame - > prefixSize ( ) , frame - > pts ( ) , is_mark , false ) ;
2021-09-27 13:12:53 +08:00
return true ;
2018-10-24 17:17:55 +08:00
}
2020-07-19 15:21:18 +08:00
} //namespace mediakit