2019-07-24 18:40:18 +08:00
/*
2023-12-09 16:23:51 +08:00
* Copyright ( c ) 2016 - present The ZLMediaKit project authors . All Rights Reserved .
2019-07-24 18:40:18 +08:00
*
2023-12-09 16:23:51 +08:00
* This file is part of ZLMediaKit ( https : //github.com/ZLMediaKit/ZLMediaKit).
2019-07-24 18:40:18 +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 .
2019-07-24 18:40:18 +08:00
*/
# include "Frame.h"
2021-03-30 10:59:15 +08:00
# include "Common/Parser.h"
2022-11-29 11:07:13 +08:00
# include "Common/Stamp.h"
2023-06-03 17:34:34 +08:00
# include "Common/MediaSource.h"
2022-11-29 11:07:13 +08:00
2023-12-09 16:23:51 +08:00
# if defined(ENABLE_MP4)
# include "mov-format.h"
# endif
# if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY)
# include "mpeg-proto.h"
# endif
2019-07-24 18:40:18 +08:00
using namespace std ;
using namespace toolkit ;
2021-01-23 09:44:37 +08:00
namespace toolkit {
StatisticImp ( mediakit : : Frame ) ;
StatisticImp ( mediakit : : FrameImp ) ;
}
2019-07-24 18:40:18 +08:00
namespace mediakit {
Frame : : Ptr Frame : : getCacheAbleFrame ( const Frame : : Ptr & frame ) {
if ( frame - > cacheAble ( ) ) {
return frame ;
}
return std : : make_shared < FrameCacheAble > ( frame ) ;
}
2024-10-13 00:25:40 +08:00
FrameStamp : : FrameStamp ( Frame : : Ptr frame ) {
2023-12-09 22:34:22 +08:00
setIndex ( frame - > getIndex ( ) ) ;
2022-11-29 11:07:13 +08:00
_frame = std : : move ( frame ) ;
2024-10-13 00:25:40 +08:00
}
FrameStamp : : FrameStamp ( Frame : : Ptr frame , Stamp & stamp , int modify_stamp )
: FrameStamp ( std : : move ( frame ) ) {
2024-09-19 14:53:50 +08:00
// kModifyStampSystem时采用系统时间戳, kModifyStampRelative采用相对时间戳 [AUTO-TRANSLATED:54dd5685]
// When using kModifyStampSystem, the system timestamp is used, and when using kModifyStampRelative, the relative timestamp is used.
2023-06-03 17:34:34 +08:00
stamp . revise ( _frame - > dts ( ) , _frame - > pts ( ) , _dts , _pts , modify_stamp = = ProtocolOption : : kModifyStampSystem ) ;
2022-11-29 11:07:13 +08:00
}
2024-10-13 00:25:40 +08:00
void FrameStamp : : setStamp ( int64_t dts , int64_t pts ) {
_dts = dts ;
_pts = pts ;
}
2021-06-16 11:14:10 +08:00
TrackType getTrackType ( CodecId codecId ) {
switch ( codecId ) {
2023-12-09 16:23:51 +08:00
# define XX(name, type, value, str, mpeg_id, mp4_id) case name : return type;
2021-06-16 11:14:10 +08:00
CODEC_MAP ( XX )
# undef XX
default : return TrackInvalid ;
2020-05-11 22:33:10 +08:00
}
}
2019-07-24 18:40:18 +08:00
2023-12-09 16:23:51 +08:00
# if defined(ENABLE_MP4)
int getMovIdByCodec ( CodecId codecId ) {
switch ( codecId ) {
# define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mp4_id;
CODEC_MAP ( XX )
# undef XX
default : return MOV_OBJECT_NONE ;
}
}
CodecId getCodecByMovId ( int object_id ) {
if ( object_id = = MOV_OBJECT_NONE ) {
return CodecInvalid ;
}
2023-12-31 22:14:58 +08:00
# define XX(name, type, value, str, mpeg_id, mp4_id) { mp4_id, name },
static map < int , CodecId > s_map = { CODEC_MAP ( XX ) } ;
2023-12-09 16:23:51 +08:00
# undef XX
2023-12-31 22:14:58 +08:00
auto it = s_map . find ( object_id ) ;
if ( it = = s_map . end ( ) ) {
WarnL < < " Unsupported mov: " < < object_id ;
return CodecInvalid ;
2023-12-09 16:23:51 +08:00
}
2023-12-31 22:14:58 +08:00
return it - > second ;
2023-12-09 16:23:51 +08:00
}
# endif
# if defined(ENABLE_HLS) || defined(ENABLE_RTPPROXY)
int getMpegIdByCodec ( CodecId codec ) {
switch ( codec ) {
# define XX(name, type, value, str, mpeg_id, mp4_id) case name : return mpeg_id;
CODEC_MAP ( XX )
# undef XX
default : return PSI_STREAM_RESERVED ;
}
}
CodecId getCodecByMpegId ( int mpeg_id ) {
2023-12-31 22:14:58 +08:00
if ( mpeg_id = = PSI_STREAM_RESERVED | | mpeg_id = = 0xBD ) {
2024-09-19 14:53:50 +08:00
// 海康的 PS 流中会有0xBD 的包 [AUTO-TRANSLATED:32a250cb]
// Hikvision's PS stream will have 0xBD packets.
2023-12-09 16:23:51 +08:00
return CodecInvalid ;
}
2023-12-31 22:14:58 +08:00
# define XX(name, type, value, str, mpeg_id, mp4_id) { mpeg_id, name },
static map < int , CodecId > s_map = { CODEC_MAP ( XX ) } ;
2023-12-09 16:23:51 +08:00
# undef XX
2023-12-31 22:14:58 +08:00
auto it = s_map . find ( mpeg_id ) ;
if ( it = = s_map . end ( ) ) {
WarnL < < " Unsupported mpeg: " < < mpeg_id ;
return CodecInvalid ;
2023-12-09 16:23:51 +08:00
}
2023-12-31 22:14:58 +08:00
return it - > second ;
2023-12-09 16:23:51 +08:00
}
# endif
2021-06-16 11:14:10 +08:00
const char * getCodecName ( CodecId codec ) {
2021-03-30 10:59:15 +08:00
switch ( codec ) {
2023-12-09 16:23:51 +08:00
# define XX(name, type, value, str, mpeg_id, mp4_id) case name : return str;
2021-06-16 11:14:10 +08:00
CODEC_MAP ( XX )
# undef XX
default : return " invalid " ;
2021-03-30 10:59:15 +08:00
}
}
2023-12-09 16:23:51 +08:00
# define XX(name, type, value, str, mpeg_id, mp4_id) {str, name},
static map < string , CodecId , StrCaseCompare > codec_map = { CODEC_MAP ( XX ) } ;
2021-06-16 11:14:10 +08:00
# undef XX
2021-03-30 10:59:15 +08:00
CodecId getCodecId ( const string & str ) {
auto it = codec_map . find ( str ) ;
return it = = codec_map . end ( ) ? CodecInvalid : it - > second ;
}
static map < string , TrackType , StrCaseCompare > track_str_map = {
{ " video " , TrackVideo } ,
{ " audio " , TrackAudio } ,
{ " application " , TrackApplication }
} ;
TrackType getTrackType ( const string & str ) {
auto it = track_str_map . find ( str ) ;
return it = = track_str_map . end ( ) ? TrackInvalid : it - > second ;
}
const char * getTrackString ( TrackType type ) {
switch ( type ) {
case TrackVideo : return " video " ;
case TrackAudio : return " audio " ;
case TrackApplication : return " application " ;
default : return " invalid " ;
}
}
2021-07-09 13:38:20 +08:00
const char * CodecInfo : : getCodecName ( ) const {
2020-05-15 18:08:54 +08:00
return mediakit : : getCodecName ( getCodecId ( ) ) ;
}
2021-07-09 13:38:20 +08:00
TrackType CodecInfo : : getTrackType ( ) const {
2020-05-15 18:08:54 +08:00
return mediakit : : getTrackType ( getCodecId ( ) ) ;
}
2021-04-26 18:26:07 +08:00
2023-12-09 16:23:51 +08:00
std : : string CodecInfo : : getTrackTypeStr ( ) const {
return getTrackString ( getTrackType ( ) ) ;
}
2021-04-26 18:26:07 +08:00
static size_t constexpr kMaxFrameCacheSize = 100 ;
bool FrameMerger : : willFlush ( const Frame : : Ptr & frame ) const {
2021-07-09 13:38:20 +08:00
if ( _frame_cache . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// 缓存为空 [AUTO-TRANSLATED:b9505a19]
// Cache is empty.
2021-04-26 18:26:07 +08:00
return false ;
}
2022-05-25 15:38:32 +08:00
if ( ! frame ) {
return true ;
}
2021-04-26 18:26:07 +08:00
switch ( _type ) {
case none : {
2024-09-19 14:53:50 +08:00
// frame不是完整的帧, 我们合并为一帧 [AUTO-TRANSLATED:00e9f200]
// The frame is not a complete frame, we merge it into one frame.
2021-04-26 18:26:07 +08:00
bool new_frame = false ;
switch ( frame - > getCodecId ( ) ) {
case CodecH264 :
case CodecH265 : {
2024-09-19 14:53:50 +08:00
// 如果是新的一帧,前面的缓存需要输出 [AUTO-TRANSLATED:b4deff81]
// If it is a new frame, the previous cache needs to be output.
2021-04-26 18:26:07 +08:00
new_frame = frame - > prefixSize ( ) ;
break ;
}
default : break ;
}
2024-09-19 14:53:50 +08:00
// 遇到新帧、或时间戳变化或缓存太多, 防止内存溢出, 则flush输出 [AUTO-TRANSLATED:0292964a]
// When encountering a new frame, or a timestamp change, or too much cache, flush the output to prevent memory overflow.
2021-07-09 13:38:20 +08:00
return new_frame | | _frame_cache . back ( ) - > dts ( ) ! = frame - > dts ( ) | | _frame_cache . size ( ) > kMaxFrameCacheSize ;
2021-04-26 18:26:07 +08:00
}
case mp4_nal_size :
case h264_prefix : {
2021-07-09 13:38:20 +08:00
if ( ! _have_decode_able_frame ) {
2024-09-19 14:53:50 +08:00
// 缓存中没有有效的能解码的帧, 所以这次不flush [AUTO-TRANSLATED:5d860722]
// There are no valid frames that can be decoded in the cache, so no flush this time.
2021-07-09 13:38:20 +08:00
return _frame_cache . size ( ) > kMaxFrameCacheSize ;
2021-07-07 11:02:05 +08:00
}
2021-08-18 22:19:36 +08:00
if ( _frame_cache . back ( ) - > dts ( ) ! = frame - > dts ( ) | | frame - > decodeAble ( ) | | frame - > configFrame ( ) ) {
2024-09-19 14:53:50 +08:00
// 时间戳变化了,或新的一帧, 或遇到config帧, 立即flush [AUTO-TRANSLATED:8c2523b1]
// When the timestamp changes, or a new frame, or a config frame is encountered, flush immediately.
2021-04-26 18:26:07 +08:00
return true ;
}
2021-07-09 13:38:20 +08:00
return _frame_cache . size ( ) > kMaxFrameCacheSize ;
2021-04-26 18:26:07 +08:00
}
default : /*不可达*/ assert ( 0 ) ; return true ;
}
}
void FrameMerger : : doMerge ( BufferLikeString & merged , const Frame : : Ptr & frame ) const {
switch ( _type ) {
case none : {
2024-09-19 14:53:50 +08:00
// 此处是合并ps解析输出的流, 解析出的流可能是半帧或多帧, 不能简单的根据nal type过滤 [AUTO-TRANSLATED:4a231bdc]
// Here, the PS parsing output stream is merged. The parsed stream may be half a frame or multiple frames, and cannot be simply filtered according to the nal type.
// 此流程只用于合并ps解析输出为H264/H265, 后面流程有split和忽略无效帧操作 [AUTO-TRANSLATED:2d40274e]
// This process is only used to merge PS parsing output into H264/H265. The subsequent process has split and ignore invalid frame operations.
2021-04-26 18:26:07 +08:00
merged . append ( frame - > data ( ) , frame - > size ( ) ) ;
break ;
}
case h264_prefix : {
if ( frame - > prefixSize ( ) ) {
merged . append ( frame - > data ( ) , frame - > size ( ) ) ;
} else {
merged . append ( " \x00 \x00 \x00 \x01 " , 4 ) ;
merged . append ( frame - > data ( ) , frame - > size ( ) ) ;
}
break ;
}
case mp4_nal_size : {
uint32_t nalu_size = ( uint32_t ) ( frame - > size ( ) - frame - > prefixSize ( ) ) ;
nalu_size = htonl ( nalu_size ) ;
merged . append ( ( char * ) & nalu_size , 4 ) ;
merged . append ( frame - > data ( ) + frame - > prefixSize ( ) , frame - > size ( ) - frame - > prefixSize ( ) ) ;
break ;
}
default : /*不可达*/ assert ( 0 ) ; break ;
}
}
2021-06-28 10:35:08 +08:00
2023-12-09 16:23:51 +08:00
static bool isNeedMerge ( CodecId codec ) {
switch ( codec ) {
case CodecH264 :
case CodecH265 : return true ;
default : return false ;
}
}
2022-10-16 19:49:56 +08:00
bool FrameMerger : : inputFrame ( const Frame : : Ptr & frame , onOutput cb , BufferLikeString * buffer ) {
2023-12-09 16:23:51 +08:00
if ( frame & & ! isNeedMerge ( frame - > getCodecId ( ) ) ) {
cb ( frame - > dts ( ) , frame - > pts ( ) , frame , true ) ;
return true ;
}
2021-07-07 11:02:05 +08:00
if ( willFlush ( frame ) ) {
2021-07-09 13:38:20 +08:00
Frame : : Ptr back = _frame_cache . back ( ) ;
2021-04-26 18:26:07 +08:00
Buffer : : Ptr merged_frame = back ;
2021-07-09 13:38:20 +08:00
bool have_key_frame = back - > keyFrame ( ) ;
2021-04-26 18:26:07 +08:00
2021-07-09 13:38:20 +08:00
if ( _frame_cache . size ( ) ! = 1 | | _type = = mp4_nal_size | | buffer ) {
2024-09-19 14:53:50 +08:00
// 在MP4模式下, 一帧数据也需要在前添加nalu_size [AUTO-TRANSLATED:4a7e5c20]
// In MP4 mode, a frame of data also needs to add nalu_size in front.
2021-07-09 13:38:20 +08:00
BufferLikeString tmp ;
BufferLikeString & merged = buffer ? * buffer : tmp ;
if ( ! buffer ) {
tmp . reserve ( back - > size ( ) + 1024 ) ;
}
_frame_cache . for_each ( [ & ] ( const Frame : : Ptr & frame ) {
2021-04-26 18:26:07 +08:00
doMerge ( merged , frame ) ;
if ( frame - > keyFrame ( ) ) {
2021-07-09 13:38:20 +08:00
have_key_frame = true ;
2021-04-26 18:26:07 +08:00
}
} ) ;
2021-07-09 13:38:20 +08:00
merged_frame = std : : make_shared < BufferOffset < BufferLikeString > > ( buffer ? merged : std : : move ( merged ) ) ;
2021-04-26 18:26:07 +08:00
}
2021-07-09 13:38:20 +08:00
cb ( back - > dts ( ) , back - > pts ( ) , merged_frame , have_key_frame ) ;
_frame_cache . clear ( ) ;
_have_decode_able_frame = false ;
2021-04-26 18:26:07 +08:00
}
2021-07-07 11:02:05 +08:00
2022-05-25 15:38:32 +08:00
if ( ! frame ) {
return false ;
}
2021-07-09 13:38:20 +08:00
if ( frame - > decodeAble ( ) ) {
_have_decode_able_frame = true ;
}
2022-10-16 19:49:56 +08:00
_cb = std : : move ( cb ) ;
2021-07-09 13:38:20 +08:00
_frame_cache . emplace_back ( Frame : : getCacheAbleFrame ( frame ) ) ;
2021-09-27 13:12:53 +08:00
return true ;
2021-04-26 18:26:07 +08:00
}
FrameMerger : : FrameMerger ( int type ) {
_type = type ;
}
void FrameMerger : : clear ( ) {
2021-07-09 13:38:20 +08:00
_frame_cache . clear ( ) ;
_have_decode_able_frame = false ;
2021-04-26 18:26:07 +08:00
}
2022-10-16 19:49:56 +08:00
void FrameMerger : : flush ( ) {
if ( _cb ) {
inputFrame ( nullptr , std : : move ( _cb ) , nullptr ) ;
}
clear ( ) ;
}
2022-11-01 11:44:50 +08:00
/**
* 写 帧 接 口 转 function , 辅 助 类
2024-09-19 14:53:50 +08:00
* Write frame interface to function , auxiliary class
* [ AUTO - TRANSLATED : ce04a5e9 ]
2022-11-01 11:44:50 +08:00
*/
class FrameWriterInterfaceHelper : public FrameWriterInterface {
public :
2022-11-01 16:52:52 +08:00
using Ptr = std : : shared_ptr < FrameWriterInterfaceHelper > ;
using onWriteFrame = std : : function < bool ( const Frame : : Ptr & frame ) > ;
2022-11-01 11:44:50 +08:00
/**
* inputFrame后触发onWriteFrame回调
2024-09-19 14:53:50 +08:00
* Trigger onWriteFrame callback after inputFrame
* [ AUTO - TRANSLATED : 169e5944 ]
2022-11-01 11:44:50 +08:00
*/
2022-11-01 16:52:52 +08:00
FrameWriterInterfaceHelper ( onWriteFrame cb ) { _callback = std : : move ( cb ) ; }
2022-11-01 11:44:50 +08:00
/**
* 写 入 帧 数 据
2024-09-19 14:53:50 +08:00
* Write frame data
* [ AUTO - TRANSLATED : d46c6fc2 ]
2022-11-01 11:44:50 +08:00
*/
2022-11-01 16:52:52 +08:00
bool inputFrame ( const Frame : : Ptr & frame ) override { return _callback ( frame ) ; }
2022-11-01 11:44:50 +08:00
private :
2022-11-01 16:52:52 +08:00
onWriteFrame _callback ;
2022-11-01 11:44:50 +08:00
} ;
2022-11-01 16:52:52 +08:00
FrameWriterInterface * FrameDispatcher : : addDelegate ( std : : function < bool ( const Frame : : Ptr & frame ) > cb ) {
return addDelegate ( std : : make_shared < FrameWriterInterfaceHelper > ( std : : move ( cb ) ) ) ;
2022-11-01 11:44:50 +08:00
}
2022-10-16 19:49:56 +08:00
2020-05-11 22:33:10 +08:00
} //namespace mediakit