mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-24 11:40:37 +08:00
AI automatically translates all comments in the code into English (#3917)
This commit is contained in:
parent
046de691cb
commit
4152dcd409
@ -1 +1 @@
|
||||
Subproject commit a6e30e41f0c52f9d36c41eb79ac69b50020a6ac9
|
||||
Subproject commit ac6ae2d76cb7463243ade44e6aa75a552e82e5c9
|
@ -44,53 +44,76 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//输出日志到shell
|
||||
// 输出日志到shell [AUTO-TRANSLATED:6523242b]
|
||||
// cpp
|
||||
// Output log to shell
|
||||
#define LOG_CONSOLE (1 << 0)
|
||||
//输出日志到文件
|
||||
// 输出日志到文件 [AUTO-TRANSLATED:8ffaf1e0]
|
||||
// Output log to file
|
||||
#define LOG_FILE (1 << 1)
|
||||
//输出日志到回调函数(mk_events::on_mk_log)
|
||||
// 输出日志到回调函数(mk_events::on_mk_log) [AUTO-TRANSLATED:616561c1]
|
||||
// Output log to callback function (mk_events::on_mk_log)
|
||||
#define LOG_CALLBACK (1 << 2)
|
||||
|
||||
//向下兼容
|
||||
// 向下兼容 [AUTO-TRANSLATED:5b800712]
|
||||
// Downward compatibility
|
||||
#define mk_env_init1 mk_env_init2
|
||||
|
||||
//回调user_data回调函数
|
||||
// 回调user_data回调函数 [AUTO-TRANSLATED:ced626fb]
|
||||
// Callback user_data callback function
|
||||
typedef void(API_CALL *on_user_data_free)(void *user_data);
|
||||
|
||||
typedef struct {
|
||||
// 线程数
|
||||
// 线程数 [AUTO-TRANSLATED:f7fc7650]
|
||||
// Number of threads
|
||||
int thread_num;
|
||||
|
||||
// 日志级别,支持0~4
|
||||
// 日志级别,支持0~4 [AUTO-TRANSLATED:f4d77bb5]
|
||||
// Log level, supports 0~4
|
||||
int log_level;
|
||||
//控制日志输出的掩模,请查看LOG_CONSOLE、LOG_FILE、LOG_CALLBACK等宏
|
||||
// 控制日志输出的掩模,请查看LOG_CONSOLE、LOG_FILE、LOG_CALLBACK等宏 [AUTO-TRANSLATED:71de1d10]
|
||||
// Control the mask of log output, please refer to LOG_CONSOLE, LOG_FILE, LOG_CALLBACK macros
|
||||
int log_mask;
|
||||
//文件日志保存路径,路径可以不存在(内部可以创建文件夹),设置为NULL关闭日志输出至文件
|
||||
// 文件日志保存路径,路径可以不存在(内部可以创建文件夹),设置为NULL关闭日志输出至文件 [AUTO-TRANSLATED:d0989d3c]
|
||||
// File log save path, the path can be non-existent (folders can be created internally), set to NULL to disable log output to file
|
||||
const char *log_file_path;
|
||||
//文件日志保存天数,设置为0关闭日志文件
|
||||
// 文件日志保存天数,设置为0关闭日志文件 [AUTO-TRANSLATED:04253cb0]
|
||||
// File log save days, set to 0 to disable log file
|
||||
int log_file_days;
|
||||
|
||||
// 配置文件是内容还是路径
|
||||
// 配置文件是内容还是路径 [AUTO-TRANSLATED:b946f030]
|
||||
// Is the configuration file content or path
|
||||
int ini_is_path;
|
||||
// 配置文件内容或路径,可以为NULL,如果该文件不存在,那么将导出默认配置至该文件
|
||||
// 配置文件内容或路径,可以为NULL,如果该文件不存在,那么将导出默认配置至该文件 [AUTO-TRANSLATED:aeaa4583]
|
||||
// Configuration file content or path, can be NULL, if the file does not exist, then the default configuration will be exported to the file
|
||||
const char *ini;
|
||||
|
||||
// ssl证书是内容还是路径
|
||||
// ssl证书是内容还是路径 [AUTO-TRANSLATED:820671ab]
|
||||
// Is the ssl certificate content or path
|
||||
int ssl_is_path;
|
||||
// ssl证书内容或路径,可以为NULL
|
||||
// ssl证书内容或路径,可以为NULL [AUTO-TRANSLATED:c32fffb6]
|
||||
// ssl certificate content or path, can be NULL
|
||||
const char *ssl;
|
||||
// 证书密码,可以为NULL
|
||||
// 证书密码,可以为NULL [AUTO-TRANSLATED:b8c9c173]
|
||||
// Certificate password, can be NULL
|
||||
const char *ssl_pwd;
|
||||
} mk_config;
|
||||
|
||||
/**
|
||||
* 初始化环境,调用该库前需要先调用此函数
|
||||
* @param cfg 库运行相关参数
|
||||
* Initialize the environment, you need to call this function before calling this library
|
||||
* @param cfg Library running related parameters
|
||||
|
||||
* [AUTO-TRANSLATED:58d6d220]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_env_init(const mk_config *cfg);
|
||||
|
||||
/**
|
||||
* 关闭所有服务器,请在main函数退出时调用
|
||||
* Close all servers, please call this function when exiting the main function
|
||||
|
||||
* [AUTO-TRANSLATED:f1148928]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_stop_all_server();
|
||||
|
||||
@ -106,6 +129,19 @@ API_EXPORT void API_CALL mk_stop_all_server();
|
||||
* @param ssl_is_path ssl证书是内容还是路径
|
||||
* @param ssl ssl证书内容或路径,可以为NULL
|
||||
* @param ssl_pwd 证书密码,可以为NULL
|
||||
* mk_env_init version of basic type parameters, for easy calling by other languages
|
||||
* @param thread_num Number of threads
|
||||
* @param log_level Log level, supports 0~4
|
||||
* @param log_mask Log output mode mask, please refer to LOG_CONSOLE, LOG_FILE, LOG_CALLBACK macros
|
||||
* @param log_file_path File log save path, the path can be non-existent (folders can be created internally), set to NULL to disable log output to file
|
||||
* @param log_file_days File log save days, set to 0 to disable log file
|
||||
* @param ini_is_path Is the configuration file content or path
|
||||
* @param ini Configuration file content or path, can be NULL, if the file does not exist, then the default configuration will be exported to the file
|
||||
* @param ssl_is_path Is the ssl certificate content or path
|
||||
* @param ssl ssl certificate content or path, can be NULL
|
||||
* @param ssl_pwd Certificate password, can be NULL
|
||||
|
||||
* [AUTO-TRANSLATED:12901102]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_env_init2(int thread_num,
|
||||
int log_level,
|
||||
@ -122,6 +158,11 @@ API_EXPORT void API_CALL mk_env_init2(int thread_num,
|
||||
* 设置日志文件
|
||||
* @param file_max_size 单个切片文件大小(MB)
|
||||
* @param file_max_count 切片文件个数
|
||||
* Set the log file
|
||||
* @param file_max_size Single slice file size (MB)
|
||||
* @param file_max_count Number of slice files
|
||||
|
||||
* [AUTO-TRANSLATED:59204140]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_set_log(int file_max_size, int file_max_count);
|
||||
|
||||
@ -130,6 +171,12 @@ API_EXPORT void API_CALL mk_set_log(int file_max_size, int file_max_count);
|
||||
* @deprecated 请使用mk_ini_set_option替代
|
||||
* @param key 配置项名
|
||||
* @param val 配置项值
|
||||
* Set the configuration item
|
||||
* @deprecated Please use mk_ini_set_option instead
|
||||
* @param key Configuration item name
|
||||
* @param val Configuration item value
|
||||
|
||||
* [AUTO-TRANSLATED:93d02c07]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_set_option(const char *key, const char *val);
|
||||
|
||||
@ -137,6 +184,11 @@ API_EXPORT void API_CALL mk_set_option(const char *key, const char *val);
|
||||
* 获取配置项的值
|
||||
* @deprecated 请使用mk_ini_get_option替代
|
||||
* @param key 配置项名
|
||||
* Get the value of the configuration item
|
||||
* @deprecated Please use mk_ini_get_option instead
|
||||
* @param key Configuration item name
|
||||
|
||||
* [AUTO-TRANSLATED:6222a231]
|
||||
*/
|
||||
API_EXPORT const char * API_CALL mk_get_option(const char *key);
|
||||
|
||||
@ -146,6 +198,12 @@ API_EXPORT const char * API_CALL mk_get_option(const char *key);
|
||||
* @param port htt监听端口,推荐80,传入0则随机分配
|
||||
* @param ssl 是否为ssl类型服务器
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create http[s] server
|
||||
* @param port htt listening port, recommended 80, pass in 0 to randomly allocate
|
||||
* @param ssl Whether it is an ssl type server
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:4ca78101]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_http_server_start(uint16_t port, int ssl);
|
||||
|
||||
@ -154,6 +212,12 @@ API_EXPORT uint16_t API_CALL mk_http_server_start(uint16_t port, int ssl);
|
||||
* @param port rtsp监听端口,推荐554,传入0则随机分配
|
||||
* @param ssl 是否为ssl类型服务器
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create rtsp[s] server
|
||||
* @param port rtsp listening port, recommended 554, pass in 0 to randomly allocate
|
||||
* @param ssl Whether it is an ssl type server
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:3d984d90]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_rtsp_server_start(uint16_t port, int ssl);
|
||||
|
||||
@ -162,6 +226,12 @@ API_EXPORT uint16_t API_CALL mk_rtsp_server_start(uint16_t port, int ssl);
|
||||
* @param port rtmp监听端口,推荐1935,传入0则随机分配
|
||||
* @param ssl 是否为ssl类型服务器
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create rtmp[s] server
|
||||
* @param port rtmp listening port, recommended 1935, pass in 0 to randomly allocate
|
||||
* @param ssl Whether it is an ssl type server
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:ed841271]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_rtmp_server_start(uint16_t port, int ssl);
|
||||
|
||||
@ -169,6 +239,11 @@ API_EXPORT uint16_t API_CALL mk_rtmp_server_start(uint16_t port, int ssl);
|
||||
* 创建rtp服务器
|
||||
* @param port rtp监听端口(包括udp/tcp)
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create rtp server
|
||||
* @param port rtp listening port (including udp/tcp)
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:f49af495]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port);
|
||||
|
||||
@ -176,10 +251,16 @@ API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port);
|
||||
* 创建rtc服务器
|
||||
* @param port rtc监听端口
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create rtc server
|
||||
* @param port rtc listening port
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:df151854]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port);
|
||||
|
||||
//获取webrtc answer sdp回调函数
|
||||
// 获取webrtc answer sdp回调函数 [AUTO-TRANSLATED:10c93fa9]
|
||||
// Get webrtc answer sdp callback function
|
||||
typedef void(API_CALL *on_mk_webrtc_get_answer_sdp)(void *user_data, const char *answer, const char *err);
|
||||
|
||||
/**
|
||||
@ -189,6 +270,14 @@ typedef void(API_CALL *on_mk_webrtc_get_answer_sdp)(void *user_data, const char
|
||||
* @param type webrtc插件类型,支持echo,play,push
|
||||
* @param offer webrtc offer sdp
|
||||
* @param url rtc url, 例如 rtc://__defaultVhost/app/stream?key1=val1&key2=val2
|
||||
* webrtc exchange sdp, generate answer sdp based on offer sdp
|
||||
* @param user_data Callback user pointer
|
||||
* @param cb Callback function
|
||||
* @param type webrtc plugin type, supports echo, play, push
|
||||
* @param offer webrtc offer sdp
|
||||
* @param url rtc url, for example rtc://__defaultVhost/app/stream?key1=val1&key2=val2
|
||||
|
||||
* [AUTO-TRANSLATED:ea79659b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_webrtc_get_answer_sdp(void *user_data, on_mk_webrtc_get_answer_sdp cb, const char *type,
|
||||
const char *offer, const char *url);
|
||||
@ -200,6 +289,11 @@ API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2(void *user_data, on_user_data
|
||||
* 创建srt服务器
|
||||
* @param port srt监听端口
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create srt server
|
||||
* @param port srt listening port
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
* [AUTO-TRANSLATED:250984c0]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_srt_server_start(uint16_t port);
|
||||
|
||||
@ -208,6 +302,12 @@ API_EXPORT uint16_t API_CALL mk_srt_server_start(uint16_t port);
|
||||
* 创建shell服务器
|
||||
* @param port shell监听端口
|
||||
* @return 0:失败,非0:端口号
|
||||
* Create shell server
|
||||
* @param port shell listening port
|
||||
* @return 0: failure, non-0: port number
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:66ec9a2a]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_shell_server_start(uint16_t port);
|
||||
|
||||
|
@ -23,6 +23,11 @@ typedef struct {
|
||||
* 注册或反注册MediaSource事件广播
|
||||
* @param regist 注册为1,注销为0
|
||||
* @param sender 该MediaSource对象
|
||||
* Register or unregister MediaSource event broadcast
|
||||
* @param regist Register as 1, unregister as 0
|
||||
* @param sender The MediaSource object
|
||||
|
||||
* [AUTO-TRANSLATED:d440a47c]
|
||||
*/
|
||||
void (API_CALL *on_mk_media_changed)(int regist,
|
||||
const mk_media_source sender);
|
||||
@ -33,6 +38,13 @@ typedef struct {
|
||||
* @param url_info 推流url相关信息
|
||||
* @param invoker 执行invoker返回鉴权结果
|
||||
* @param sender 该tcp客户端相关信息
|
||||
* Receive rtsp/rtmp push stream event broadcast, control push stream authentication through this event
|
||||
* @see mk_publish_auth_invoker_do
|
||||
* @param url_info Push stream url related information
|
||||
* @param invoker Execute invoker to return authentication result
|
||||
* @param sender The tcp client related information
|
||||
|
||||
* [AUTO-TRANSLATED:2a607577]
|
||||
*/
|
||||
void (API_CALL *on_mk_media_publish)(const mk_media_info url_info,
|
||||
const mk_publish_auth_invoker invoker,
|
||||
@ -44,6 +56,13 @@ typedef struct {
|
||||
* @param url_info 播放url相关信息
|
||||
* @param invoker 执行invoker返回鉴权结果
|
||||
* @param sender 播放客户端相关信息
|
||||
* Play rtsp/rtmp/http-flv/hls event broadcast, control playback authentication through this event
|
||||
* @see mk_auth_invoker_do
|
||||
* @param url_info Play url related information
|
||||
* @param invoker Execute invoker to return authentication result
|
||||
* @param sender Play client related information
|
||||
|
||||
* [AUTO-TRANSLATED:817c964d]
|
||||
*/
|
||||
void (API_CALL *on_mk_media_play)(const mk_media_info url_info,
|
||||
const mk_auth_invoker invoker,
|
||||
@ -55,6 +74,13 @@ typedef struct {
|
||||
* @param sender 播放客户端相关信息
|
||||
* @return 1 直接关闭
|
||||
* 0 等待流注册
|
||||
* This event will be broadcast after the stream is not found. Please pull the stream or other methods to generate the stream after listening to this event, so that you can pull the stream on demand.
|
||||
* @param url_info Play url related information
|
||||
* @param sender Play client related information
|
||||
* @return 1 Close directly
|
||||
* 0 Wait for stream registration
|
||||
|
||||
* [AUTO-TRANSLATED:468e7356]
|
||||
*/
|
||||
int (API_CALL *on_mk_media_not_found)(const mk_media_info url_info,
|
||||
const mk_sock_info sender);
|
||||
@ -62,6 +88,10 @@ typedef struct {
|
||||
/**
|
||||
* 某个流无人消费时触发,目的为了实现无人观看时主动断开拉流等业务逻辑
|
||||
* @param sender 该MediaSource对象
|
||||
* Triggered when a stream is not consumed by anyone, the purpose is to achieve business logic such as actively disconnecting the pull stream when no one is watching
|
||||
* @param sender The MediaSource object
|
||||
|
||||
* [AUTO-TRANSLATED:348078cb]
|
||||
*/
|
||||
void (API_CALL *on_mk_media_no_reader)(const mk_media_source sender);
|
||||
|
||||
@ -71,6 +101,13 @@ typedef struct {
|
||||
* @param invoker 执行该invoker返回http回复
|
||||
* @param consumed 置1则说明我们要处理该事件
|
||||
* @param sender http客户端相关信息
|
||||
* Receive http api request broadcast (including GET/POST)
|
||||
* @param parser Http request content object
|
||||
* @param invoker Execute this invoker to return http reply
|
||||
* @param consumed Set to 1 if we want to handle this event
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:eb15bc74]
|
||||
*/
|
||||
void (API_CALL *on_mk_http_request)(const mk_parser parser,
|
||||
const mk_http_response_invoker invoker,
|
||||
@ -84,6 +121,14 @@ typedef struct {
|
||||
* @param is_dir path是否为文件夹
|
||||
* @param invoker 执行invoker返回本次访问文件的结果
|
||||
* @param sender http客户端相关信息
|
||||
* In the http file server, receive the broadcast of http access to files or directories, control the access permission of the http directory through this event
|
||||
* @param parser Http request content object
|
||||
* @param path File absolute path
|
||||
* @param is_dir Whether path is a folder
|
||||
* @param invoker Execute invoker to return the result of accessing the file this time
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:c49b1702]
|
||||
*/
|
||||
void (API_CALL *on_mk_http_access)(const mk_parser parser,
|
||||
const char *path,
|
||||
@ -97,6 +142,13 @@ typedef struct {
|
||||
* @param parser http请求内容对象
|
||||
* @param path 文件绝对路径,覆盖之可以重定向到其他文件
|
||||
* @param sender http客户端相关信息
|
||||
* In the http file server, receive the broadcast before http access to files or directories, you can control the mapping of http url to file path through this event
|
||||
* By overriding the path parameter in this event, you can achieve the purpose of selecting different http root directories according to virtual hosts or apps
|
||||
* @param parser Http request content object
|
||||
* @param path File absolute path, overriding it can redirect to other files
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:8b167279]
|
||||
*/
|
||||
void (API_CALL *on_mk_http_before_access)(const mk_parser parser,
|
||||
char *path,
|
||||
@ -107,6 +159,12 @@ typedef struct {
|
||||
* @param url_info 请求rtsp url相关信息
|
||||
* @param invoker 执行invoker返回是否需要rtsp专属认证
|
||||
* @param sender rtsp客户端相关信息
|
||||
* Does this rtsp stream need authentication? If so, call invoker and pass in realm, otherwise pass in empty realm
|
||||
* @param url_info Request rtsp url related information
|
||||
* @param invoker Execute invoker to return whether rtsp exclusive authentication is required
|
||||
* @param sender Rtsp client related information
|
||||
|
||||
* [AUTO-TRANSLATED:9bd81de9]
|
||||
*/
|
||||
void (API_CALL *on_mk_rtsp_get_realm)(const mk_media_info url_info,
|
||||
const mk_rtsp_get_realm_invoker invoker,
|
||||
@ -121,6 +179,16 @@ typedef struct {
|
||||
* @param must_no_encrypt 如果为true,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
|
||||
* @param invoker 执行invoker返回rtsp专属认证的密码
|
||||
* @param sender rtsp客户端信息
|
||||
* Request authentication user password event, user_name is the username, must_no_encrypt if true, then you must provide plain text password (because it is base64 authentication method at this time), otherwise it will lead to authentication failure
|
||||
* After getting the password, please call invoker and input the corresponding type of password and password type, invoker will match the password when executing
|
||||
* @param url_info Request rtsp url related information
|
||||
* @param realm Rtsp authentication realm
|
||||
* @param user_name Rtsp authentication username
|
||||
* @param must_no_encrypt If true, then you must provide plain text password (because it is base64 authentication method at this time), otherwise it will lead to authentication failure
|
||||
* @param invoker Execute invoker to return the password of rtsp exclusive authentication
|
||||
* @param sender Rtsp client information
|
||||
|
||||
* [AUTO-TRANSLATED:833da340]
|
||||
*/
|
||||
void (API_CALL *on_mk_rtsp_auth)(const mk_media_info url_info,
|
||||
const char *realm,
|
||||
@ -131,16 +199,25 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* 录制mp4分片文件成功后广播
|
||||
* Broadcast after recording mp4 fragment file successfully
|
||||
|
||||
* [AUTO-TRANSLATED:eef1d414]
|
||||
*/
|
||||
void (API_CALL *on_mk_record_mp4)(const mk_record_info mp4);
|
||||
|
||||
/**
|
||||
* 录制ts分片文件成功后广播
|
||||
* Broadcast after recording ts fragment file successfully
|
||||
|
||||
* [AUTO-TRANSLATED:b91dc9fa]
|
||||
*/
|
||||
void (API_CALL *on_mk_record_ts)(const mk_record_info ts);
|
||||
|
||||
/**
|
||||
* shell登录鉴权
|
||||
* Shell login authentication
|
||||
|
||||
* [AUTO-TRANSLATED:95784c94]
|
||||
*/
|
||||
void (API_CALL *on_mk_shell_login)(const char *user_name,
|
||||
const char *passwd,
|
||||
@ -153,6 +230,13 @@ typedef struct {
|
||||
* @param total_bytes 耗费上下行总流量,单位字节数
|
||||
* @param total_seconds 本次tcp会话时长,单位秒
|
||||
* @param is_player 客户端是否为播放器
|
||||
* Stop rtsp/rtmp/http-flv session after traffic reporting event broadcast
|
||||
* @param url_info Play url related information
|
||||
* @param total_bytes Total traffic consumed up and down, unit bytes
|
||||
* @param total_seconds The duration of this tcp session, unit seconds
|
||||
* @param is_player Whether the client is a player
|
||||
|
||||
* [AUTO-TRANSLATED:d81d1fc3]
|
||||
*/
|
||||
void (API_CALL *on_mk_flow_report)(const mk_media_info url_info,
|
||||
size_t total_bytes,
|
||||
@ -168,6 +252,14 @@ typedef struct {
|
||||
* @param line 源文件行
|
||||
* @param function 源文件函数名
|
||||
* @param message 日志内容
|
||||
* Log output broadcast
|
||||
* @param level Log level
|
||||
* @param file Source file name
|
||||
* @param line Source file line
|
||||
* @param function Source file function name
|
||||
* @param message Log content
|
||||
|
||||
* [AUTO-TRANSLATED:5aa5cb8f]
|
||||
*/
|
||||
void (API_CALL *on_mk_log)(int level, const char *file, int line, const char *function, const char *message);
|
||||
|
||||
@ -179,12 +271,25 @@ typedef struct {
|
||||
* @param ssrc ssrc的10进制打印,通过atoi转换为整型
|
||||
* @param err 错误代码
|
||||
* @param msg 错误提示
|
||||
* Send rtp stream failure callback, applicable to rtp sending triggered by mk_media_source_start_send_rtp/mk_media_start_send_rtp interface
|
||||
* @param vhost Virtual host
|
||||
* @param app Application name
|
||||
* @param stream Stream id
|
||||
* @param ssrc Ssrc's decimal print, convert to integer through atoi
|
||||
* @param err Error code
|
||||
* @param msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:c956e89b]
|
||||
*/
|
||||
void (API_CALL *on_mk_media_send_rtp_stop)(const char *vhost, const char *app, const char *stream, const char *ssrc, int err, const char *msg);
|
||||
|
||||
/**
|
||||
* rtc sctp连接中/完成/失败/关闭回调
|
||||
* @param rtc_transport 数据通道对象
|
||||
* Rtc sctp connection in/complete/failure/close callback
|
||||
* @param rtc_transport Data channel object
|
||||
|
||||
* [AUTO-TRANSLATED:5455fb76]
|
||||
*/
|
||||
void (API_CALL *on_mk_rtc_sctp_connecting)(mk_rtc_transport rtc_transport);
|
||||
void (API_CALL *on_mk_rtc_sctp_connected)(mk_rtc_transport rtc_transport);
|
||||
@ -196,6 +301,12 @@ typedef struct {
|
||||
* @param rtc_transport 数据通道对象
|
||||
* @param msg 数据
|
||||
* @param len 数据长度
|
||||
* Rtc data channel send data callback
|
||||
* @param rtc_transport Data channel object
|
||||
* @param msg Data
|
||||
* @param len Data length
|
||||
|
||||
* [AUTO-TRANSLATED:42f75e55]
|
||||
*/
|
||||
void (API_CALL *on_mk_rtc_sctp_send)(mk_rtc_transport rtc_transport, const uint8_t *msg, size_t len);
|
||||
|
||||
@ -206,6 +317,14 @@ typedef struct {
|
||||
* @param ppid 协议id
|
||||
* @param msg 数据
|
||||
* @param len 数据长度
|
||||
* Rtc data channel receive data callback
|
||||
* @param rtc_transport Data channel object
|
||||
* @param streamId Stream id
|
||||
* @param ppid Protocol id
|
||||
* @param msg Data
|
||||
* @param len Data length
|
||||
|
||||
* [AUTO-TRANSLATED:3abda838]
|
||||
*/
|
||||
void (API_CALL *on_mk_rtc_sctp_received)(mk_rtc_transport rtc_transport, uint16_t streamId, uint32_t ppid, const uint8_t *msg, size_t len);
|
||||
|
||||
@ -215,6 +334,10 @@ typedef struct {
|
||||
/**
|
||||
* 监听ZLMediaKit里面的事件
|
||||
* @param events 各个事件的结构体,这个对象在内部会再拷贝一次,可以设置为null以便取消监听
|
||||
* Listen to events in ZLMediaKit
|
||||
* @param events The structure of each event, this object will be copied again internally, it can be set to null to cancel listening
|
||||
|
||||
* [AUTO-TRANSLATED:d3418bc6]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_events_listen(const mk_events *events);
|
||||
|
||||
|
@ -19,30 +19,42 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////RecordInfo/////////////////////////////////////////////
|
||||
//RecordInfo对象的C映射
|
||||
// RecordInfo对象的C映射 [AUTO-TRANSLATED:2c7825a6]
|
||||
// RecordInfo object's C mapping
|
||||
typedef struct mk_record_info_t *mk_record_info;
|
||||
// GMT 标准时间,单位秒
|
||||
// GMT 标准时间,单位秒 [AUTO-TRANSLATED:3b827274]
|
||||
// GMT standard time, unit is seconds
|
||||
API_EXPORT uint64_t API_CALL mk_record_info_get_start_time(const mk_record_info ctx);
|
||||
// 录像长度,单位秒
|
||||
// 录像长度,单位秒 [AUTO-TRANSLATED:1dceac0c]
|
||||
// Recording length, unit is seconds
|
||||
API_EXPORT float API_CALL mk_record_info_get_time_len(const mk_record_info ctx);
|
||||
// 文件大小,单位 BYTE
|
||||
// 文件大小,单位 BYTE [AUTO-TRANSLATED:add20c50]
|
||||
// File size, unit is BYTE
|
||||
API_EXPORT size_t API_CALL mk_record_info_get_file_size(const mk_record_info ctx);
|
||||
// 文件路径
|
||||
// 文件路径 [AUTO-TRANSLATED:c5246c5d]
|
||||
// File path
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_file_path(const mk_record_info ctx);
|
||||
// 文件名称
|
||||
// 文件名称 [AUTO-TRANSLATED:b5d7c753]
|
||||
// File name
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_file_name(const mk_record_info ctx);
|
||||
// 文件夹路径
|
||||
// 文件夹路径 [AUTO-TRANSLATED:0e5c9d26]
|
||||
// Folder path
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_folder(const mk_record_info ctx);
|
||||
// 播放路径
|
||||
// 播放路径 [AUTO-TRANSLATED:9b5c99f8]
|
||||
// Playback path
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_url(const mk_record_info ctx);
|
||||
// 应用名称
|
||||
// 应用名称 [AUTO-TRANSLATED:2aa47ea2]
|
||||
// Application name
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_vhost(const mk_record_info ctx);
|
||||
// 流 ID
|
||||
// 流 ID [AUTO-TRANSLATED:4bbe1cbe]
|
||||
// Stream ID
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_app(const mk_record_info ctx);
|
||||
// 虚拟主机
|
||||
// 虚拟主机 [AUTO-TRANSLATED:aaae9cfe]
|
||||
// Virtual host
|
||||
API_EXPORT const char *API_CALL mk_record_info_get_stream(const mk_record_info ctx);
|
||||
|
||||
//// 下面宏保障用户代码兼容性, 二进制abi不兼容,用户需要重新编译链接 /////
|
||||
// // 下面宏保障用户代码兼容性, 二进制abi不兼容,用户需要重新编译链接 ///// [AUTO-TRANSLATED:e532a596]
|
||||
// // The following macros ensure user code compatibility, binary abi is incompatible, users need to recompile and link /////
|
||||
#define mk_mp4_info mk_record_info
|
||||
#define mk_mp4_info_get_start_time mk_record_info_get_start_time
|
||||
#define mk_mp4_info_get_time_len mk_record_info_get_time_len
|
||||
@ -56,29 +68,40 @@ API_EXPORT const char *API_CALL mk_record_info_get_stream(const mk_record_info c
|
||||
#define mk_mp4_info_get_stream mk_record_info_get_stream
|
||||
|
||||
///////////////////////////////////////////Parser/////////////////////////////////////////////
|
||||
//Parser对象的C映射
|
||||
// Parser对象的C映射 [AUTO-TRANSLATED:6ceb91d6]
|
||||
// Parser object's C mapping
|
||||
typedef struct mk_parser_t *mk_parser;
|
||||
//Parser对象中Headers foreach回调
|
||||
// Parser对象中Headers foreach回调 [AUTO-TRANSLATED:4e0a6646]
|
||||
// Parser object's Headers foreach callback
|
||||
typedef void(API_CALL *on_mk_parser_header_cb)(void *user_data, const char *key, const char *val);
|
||||
//Parser::Method(),获取命令字,譬如GET/POST
|
||||
// Parser::Method(),获取命令字,譬如GET/POST [AUTO-TRANSLATED:904ebe57]
|
||||
// Parser::Method(), get the command word, such as GET/POST
|
||||
API_EXPORT const char* API_CALL mk_parser_get_method(const mk_parser ctx);
|
||||
//Parser::Url(),获取HTTP的访问url(不包括?后面的参数)
|
||||
// Parser::Url(),获取HTTP的访问url(不包括?后面的参数) [AUTO-TRANSLATED:75f320c5]
|
||||
// Parser::Url(), get the HTTP access url (excluding the parameters after ?)
|
||||
API_EXPORT const char* API_CALL mk_parser_get_url(const mk_parser ctx);
|
||||
//Parser::Params(),?后面的参数字符串
|
||||
// Parser::Params(),?后面的参数字符串 [AUTO-TRANSLATED:3745fec0]
|
||||
// Parser::Params(), the parameter string after ?
|
||||
API_EXPORT const char* API_CALL mk_parser_get_url_params(const mk_parser ctx);
|
||||
//Parser::getUrlArgs()["key"],获取?后面的参数中的特定参数
|
||||
// Parser::getUrlArgs()["key"],获取?后面的参数中的特定参数 [AUTO-TRANSLATED:425e4b61]
|
||||
// Parser::getUrlArgs()["key"], get the specific parameter in the parameters after ?
|
||||
API_EXPORT const char* API_CALL mk_parser_get_url_param(const mk_parser ctx,const char *key);
|
||||
//Parser::Tail(),获取协议相关信息,譬如 HTTP/1.1
|
||||
// Parser::Tail(),获取协议相关信息,譬如 HTTP/1.1 [AUTO-TRANSLATED:786534b6]
|
||||
// Parser::Tail(), get protocol related information, such as HTTP/1.1
|
||||
API_EXPORT const char* API_CALL mk_parser_get_tail(const mk_parser ctx);
|
||||
//Parser::getValues()["key"],获取HTTP头中特定字段
|
||||
// Parser::getValues()["key"],获取HTTP头中特定字段 [AUTO-TRANSLATED:1c210637]
|
||||
// Parser::getValues()["key"], get the specific field in the HTTP header
|
||||
API_EXPORT const char* API_CALL mk_parser_get_header(const mk_parser ctx,const char *key);
|
||||
//Parser::Content(),获取HTTP body
|
||||
// Parser::Content(),获取HTTP body [AUTO-TRANSLATED:fb05b253]
|
||||
// Parser::Content(), get the HTTP body
|
||||
API_EXPORT const char* API_CALL mk_parser_get_content(const mk_parser ctx, size_t *length);
|
||||
//循环获取所有header
|
||||
// 循环获取所有header [AUTO-TRANSLATED:9fd7571a]
|
||||
// Loop to get all headers
|
||||
API_EXPORT void API_CALL mk_parser_headers_for_each(const mk_parser ctx, on_mk_parser_header_cb cb, void *user_data);
|
||||
|
||||
///////////////////////////////////////////MediaInfo/////////////////////////////////////////////
|
||||
//MediaInfo对象的C映射
|
||||
// MediaInfo对象的C映射 [AUTO-TRANSLATED:f9649086]
|
||||
// MediaInfo object's C mapping
|
||||
typedef struct mk_media_info_t *mk_media_info;
|
||||
//MediaInfo::param_strs
|
||||
API_EXPORT const char* API_CALL mk_media_info_get_params(const mk_media_info ctx);
|
||||
@ -97,9 +120,11 @@ API_EXPORT uint16_t API_CALL mk_media_info_get_port(const mk_media_info ctx);
|
||||
|
||||
|
||||
///////////////////////////////////////////MediaSource/////////////////////////////////////////////
|
||||
//MediaSource对象的C映射
|
||||
// MediaSource对象的C映射 [AUTO-TRANSLATED:feb50a09]
|
||||
// MediaSource object's C mapping
|
||||
typedef struct mk_media_source_t *mk_media_source;
|
||||
//查找MediaSource的回调函数
|
||||
// 查找MediaSource的回调函数 [AUTO-TRANSLATED:e8b54cf9]
|
||||
// Callback function to find MediaSource
|
||||
typedef void(API_CALL *on_mk_media_source_find_cb)(void *user_data, const mk_media_source ctx);
|
||||
|
||||
//MediaSource::getSchema()
|
||||
@ -126,7 +151,8 @@ API_EXPORT int API_CALL mk_media_source_broadcast_msg(const mk_media_source ctx,
|
||||
API_EXPORT const char* API_CALL mk_media_source_get_origin_url(const mk_media_source ctx);
|
||||
// MediaSource::getOriginType()
|
||||
API_EXPORT int API_CALL mk_media_source_get_origin_type(const mk_media_source ctx);
|
||||
// MediaSource::getOriginTypeStr(), 使用后请用mk_free释放返回值
|
||||
// MediaSource::getOriginTypeStr(), 使用后请用mk_free释放返回值 [AUTO-TRANSLATED:d612ec22]
|
||||
// MediaSource::getOriginTypeStr(), please use mk_free to release the return value after use
|
||||
API_EXPORT const char *API_CALL mk_media_source_get_origin_type_str(const mk_media_source ctx);
|
||||
// MediaSource::getCreateStamp()
|
||||
API_EXPORT uint64_t API_CALL mk_media_source_get_create_stamp(const mk_media_source ctx);
|
||||
@ -149,6 +175,20 @@ API_EXPORT uint64_t API_CALL mk_media_source_get_alive_second(const mk_media_sou
|
||||
* @param ctx 对象
|
||||
* @param force 是否强制关闭,如果强制关闭,在有人观看的情况下也会关闭
|
||||
* @return 0代表失败,1代表成功
|
||||
* Live sources are called MediaSource in ZLMediaKit,
|
||||
* Currently, there are 3 types, namely RtmpMediaSource, RtspMediaSource, HlsMediaSource
|
||||
* The source is generated in both passive and active ways:
|
||||
* Passive ways are rtsp/rtmp/rtp push stream, mp4 on-demand
|
||||
* Active ways include objects created by mk_media_create (DevChannel), objects created by mk_proxy_player_create (PlayerProxy)
|
||||
* You don't need to do anything for passive ways, ZLMediaKit has already adapted the MediaSource::close() event by default, which will close the live stream
|
||||
* For active ways, you need to set the callback of this event, you need to choose to delete the object yourself
|
||||
* You can set the callback through the mk_proxy_player_set_on_close and mk_media_set_on_close functions,
|
||||
* Please delete the object in the callback to complete the media closure, otherwise why call the mk_media_source_close function?
|
||||
* @param ctx object
|
||||
* @param force Whether to force closure, if forced closure, it will be closed even if someone is watching
|
||||
* @return 0 means failure, 1 means success
|
||||
|
||||
* [AUTO-TRANSLATED:9415a405]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_source_close(const mk_media_source ctx,int force);
|
||||
//MediaSource::seekTo()
|
||||
@ -156,15 +196,20 @@ API_EXPORT int API_CALL mk_media_source_seek_to(const mk_media_source ctx,uint32
|
||||
|
||||
/**
|
||||
* rtp推流成功与否的回调(第一次成功后,后面将一直重试)
|
||||
* Callback for whether rtp push stream is successful or not (after the first success, it will keep retrying)
|
||||
|
||||
* [AUTO-TRANSLATED:7e00f7fb]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_media_source_send_rtp_result)(void *user_data, uint16_t local_port, int err, const char *msg);
|
||||
|
||||
// MediaSource::startSendRtp,请参考mk_media_start_send_rtp,注意ctx参数类型不一样
|
||||
// MediaSource::startSendRtp,请参考mk_media_start_send_rtp,注意ctx参数类型不一样 [AUTO-TRANSLATED:515ab2e3]
|
||||
// MediaSource::startSendRtp, please refer to mk_media_start_send_rtp, note that the ctx parameter type is different
|
||||
API_EXPORT void API_CALL mk_media_source_start_send_rtp(const mk_media_source ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, on_mk_media_source_send_rtp_result cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_source_start_send_rtp2(const mk_media_source ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, on_mk_media_source_send_rtp_result cb, void *user_data, on_user_data_free user_data_free);
|
||||
API_EXPORT void API_CALL mk_media_source_start_send_rtp3(const mk_media_source ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, mk_ini options, on_mk_media_source_send_rtp_result cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_source_start_send_rtp4(const mk_media_source ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, mk_ini options, on_mk_media_source_send_rtp_result cb,void *user_data, on_user_data_free user_data_free);
|
||||
//MediaSource::stopSendRtp,请参考mk_media_stop_send_rtp,注意ctx参数类型不一样
|
||||
// MediaSource::stopSendRtp,请参考mk_media_stop_send_rtp,注意ctx参数类型不一样 [AUTO-TRANSLATED:415fe454]
|
||||
// MediaSource::stopSendRtp, please refer to mk_media_stop_send_rtp, note that the ctx parameter type is different
|
||||
API_EXPORT int API_CALL mk_media_source_stop_send_rtp(const mk_media_source ctx);
|
||||
|
||||
//MediaSource::find()
|
||||
@ -186,18 +231,29 @@ API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_s
|
||||
const char *vhost, const char *app, const char *stream);
|
||||
|
||||
///////////////////////////////////////////HttpBody/////////////////////////////////////////////
|
||||
// HttpBody对象的C映射 [AUTO-TRANSLATED:d8025ad9]
|
||||
// cpp
|
||||
//HttpBody对象的C映射
|
||||
typedef struct mk_http_body_t *mk_http_body;
|
||||
/**
|
||||
* 生成HttpStringBody
|
||||
* @param str 字符串指针
|
||||
* @param len 字符串长度,为0则用strlen获取
|
||||
* Generate HttpStringBody
|
||||
* @param str String pointer
|
||||
* @param len String length, if it is 0, use strlen to get it
|
||||
|
||||
* [AUTO-TRANSLATED:7f828392]
|
||||
*/
|
||||
API_EXPORT mk_http_body API_CALL mk_http_body_from_string(const char *str,size_t len);
|
||||
|
||||
/**
|
||||
* 生成HttpBufferBody
|
||||
* @param buffer mk_buffer对象
|
||||
* Generate HttpBufferBody
|
||||
* @param buffer mk_buffer object
|
||||
|
||||
* [AUTO-TRANSLATED:2d31a2e4]
|
||||
*/
|
||||
API_EXPORT mk_http_body API_CALL mk_http_body_from_buffer(mk_buffer buffer);
|
||||
|
||||
@ -205,6 +261,10 @@ API_EXPORT mk_http_body API_CALL mk_http_body_from_buffer(mk_buffer buffer);
|
||||
/**
|
||||
* 生成HttpFileBody
|
||||
* @param file_path 文件完整路径
|
||||
* Generate HttpFileBody
|
||||
* @param file_path File full path
|
||||
|
||||
* [AUTO-TRANSLATED:4823ab7f]
|
||||
*/
|
||||
API_EXPORT mk_http_body API_CALL mk_http_body_from_file(const char *file_path);
|
||||
|
||||
@ -212,15 +272,24 @@ API_EXPORT mk_http_body API_CALL mk_http_body_from_file(const char *file_path);
|
||||
* 生成HttpMultiFormBody
|
||||
* @param key_val 参数key-value
|
||||
* @param file_path 文件完整路径
|
||||
* Generate HttpMultiFormBody
|
||||
* @param key_val Parameter key-value
|
||||
* @param file_path File full path
|
||||
|
||||
* [AUTO-TRANSLATED:17976911]
|
||||
*/
|
||||
API_EXPORT mk_http_body API_CALL mk_http_body_from_multi_form(const char *key_val[],const char *file_path);
|
||||
|
||||
/**
|
||||
* 销毁HttpBody
|
||||
* Destroy HttpBody
|
||||
|
||||
* [AUTO-TRANSLATED:a1169b76]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_body_release(mk_http_body ctx);
|
||||
|
||||
///////////////////////////////////////////HttpResponseInvoker/////////////////////////////////////////////
|
||||
// HttpSession::HttpResponseInvoker对象的C映射 [AUTO-TRANSLATED:89287e03]
|
||||
// HttpSession::HttpResponseInvoker对象的C映射
|
||||
typedef struct mk_http_response_invoker_t *mk_http_response_invoker;
|
||||
|
||||
@ -229,6 +298,12 @@ typedef struct mk_http_response_invoker_t *mk_http_response_invoker;
|
||||
* @param response_code 譬如200
|
||||
* @param response_header 返回的http头,譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
|
||||
* @param response_body body对象
|
||||
* HttpSession::HttpResponseInvoker(const string &codeOut, const StrCaseMap &headerOut, const HttpBody::Ptr &body);
|
||||
* @param response_code For example 200
|
||||
* @param response_header The returned http header, for example {"Content-Type","text/html",NULL} must end with NULL
|
||||
* @param response_body Body object
|
||||
|
||||
* [AUTO-TRANSLATED:e006685a]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_response_invoker_do(const mk_http_response_invoker ctx,
|
||||
int response_code,
|
||||
@ -240,6 +315,12 @@ API_EXPORT void API_CALL mk_http_response_invoker_do(const mk_http_response_invo
|
||||
* @param response_code 譬如200
|
||||
* @param response_header 返回的http头,譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
|
||||
* @param response_content 返回的content部分,譬如一个网页内容
|
||||
* HttpSession::HttpResponseInvoker(const string &codeOut, const StrCaseMap &headerOut, const string &body);
|
||||
* @param response_code For example 200
|
||||
* @param response_header The returned http header, for example {"Content-Type","text/html",NULL} must end with NULL
|
||||
* @param response_content The returned content part, for example a web page content
|
||||
|
||||
* [AUTO-TRANSLATED:0c3cf577]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_response_invoker_do_string(const mk_http_response_invoker ctx,
|
||||
int response_code,
|
||||
@ -250,6 +331,12 @@ API_EXPORT void API_CALL mk_http_response_invoker_do_string(const mk_http_respon
|
||||
* @param request_parser 请求事件中的mk_parser对象,用于提取其中http头中的Range字段,通过该字段先fseek然后再发送文件部分片段
|
||||
* @param response_header 返回的http头,譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
|
||||
* @param response_file_path 返回的content部分,譬如/path/to/html/file
|
||||
* HttpSession::HttpResponseInvoker(const StrCaseMap &requestHeader,const StrCaseMap &responseHeader,const string &filePath);
|
||||
* @param request_parser The mk_parser object in the request event, used to extract the Range field in the http header, use this field to fseek first and then send the file part fragment
|
||||
* @param response_header The returned http header, for example {"Content-Type","text/html",NULL} must end with NULL
|
||||
* @param response_file_path The returned content part, for example /path/to/html/file
|
||||
|
||||
* [AUTO-TRANSLATED:8ed9ed9e]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_response_invoker_do_file(const mk_http_response_invoker ctx,
|
||||
const mk_parser request_parser,
|
||||
@ -258,15 +345,23 @@ API_EXPORT void API_CALL mk_http_response_invoker_do_file(const mk_http_response
|
||||
/**
|
||||
* 克隆mk_http_response_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_http_response_invoker_do
|
||||
* 如果是同步执行mk_http_response_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_http_response_invoker object, by cloning the object to a heap object, you can achieve cross-thread asynchronous execution of mk_http_response_invoker_do
|
||||
* If you execute mk_http_response_invoker_do synchronously, then there is no need to clone the object
|
||||
|
||||
* [AUTO-TRANSLATED:54c98395]
|
||||
*/
|
||||
API_EXPORT mk_http_response_invoker API_CALL mk_http_response_invoker_clone(const mk_http_response_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_response_invoker_clone_release(const mk_http_response_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////HttpAccessPathInvoker/////////////////////////////////////////////
|
||||
// HttpSession::HttpAccessPathInvoker对象的C映射 [AUTO-TRANSLATED:beb105f4]
|
||||
// HttpSession::HttpAccessPathInvoker对象的C映射
|
||||
typedef struct mk_http_access_path_invoker_t *mk_http_access_path_invoker;
|
||||
|
||||
@ -275,6 +370,12 @@ typedef struct mk_http_access_path_invoker_t *mk_http_access_path_invoker;
|
||||
* @param err_msg 如果为空,则代表鉴权通过,否则为错误提示,可以为null
|
||||
* @param access_path 运行或禁止访问的根目录,可以为null
|
||||
* @param cookie_life_second 鉴权cookie有效期
|
||||
* HttpSession::HttpAccessPathInvoker(const string &errMsg,const string &accessPath, int cookieLifeSecond);
|
||||
* @param err_msg If it is empty, it means that the authentication is passed, otherwise it is an error prompt, it can be null
|
||||
* @param access_path The root directory to run or prohibit access, it can be null
|
||||
* @param cookie_life_second Authentication cookie validity period
|
||||
*
|
||||
* [AUTO-TRANSLATED:105c76c4]
|
||||
**/
|
||||
API_EXPORT void API_CALL mk_http_access_path_invoker_do(const mk_http_access_path_invoker ctx,
|
||||
const char *err_msg,
|
||||
@ -284,20 +385,32 @@ API_EXPORT void API_CALL mk_http_access_path_invoker_do(const mk_http_access_pat
|
||||
/**
|
||||
* 克隆mk_http_access_path_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_http_access_path_invoker_do
|
||||
* 如果是同步执行mk_http_access_path_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_http_access_path_invoker object, by cloning the object to a heap object, you can achieve cross-thread asynchronous execution of mk_http_access_path_invoker_do
|
||||
* If you execute mk_http_access_path_invoker_do synchronously, then there is no need to clone the object
|
||||
|
||||
* [AUTO-TRANSLATED:ad2a71e4]
|
||||
*/
|
||||
API_EXPORT mk_http_access_path_invoker API_CALL mk_http_access_path_invoker_clone(const mk_http_access_path_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_access_path_invoker_clone_release(const mk_http_access_path_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////RtspSession::onGetRealm/////////////////////////////////////////////
|
||||
// RtspSession::onGetRealm对象的C映射 [AUTO-TRANSLATED:2355d645]
|
||||
// RtspSession::onGetRealm对象的C映射
|
||||
typedef struct mk_rtsp_get_realm_invoker_t *mk_rtsp_get_realm_invoker;
|
||||
/**
|
||||
* 执行RtspSession::onGetRealm
|
||||
* @param realm 该rtsp流是否需要开启rtsp专属鉴权,至null或空字符串则不鉴权
|
||||
* Execute RtspSession::onGetRealm
|
||||
* @param realm Whether this rtsp stream needs to enable rtsp exclusive authentication, to null or empty string does not authenticate
|
||||
|
||||
* [AUTO-TRANSLATED:ed88a88b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtsp_get_realm_invoker_do(const mk_rtsp_get_realm_invoker ctx,
|
||||
const char *realm);
|
||||
@ -305,15 +418,23 @@ API_EXPORT void API_CALL mk_rtsp_get_realm_invoker_do(const mk_rtsp_get_realm_in
|
||||
/**
|
||||
* 克隆mk_rtsp_get_realm_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_rtsp_get_realm_invoker_do
|
||||
* 如果是同步执行mk_rtsp_get_realm_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_rtsp_get_realm_invoker object, by cloning the object to a heap object, you can achieve cross-thread asynchronous execution of mk_rtsp_get_realm_invoker_do
|
||||
* If you execute mk_rtsp_get_realm_invoker_do synchronously, then there is no need to clone the object
|
||||
|
||||
* [AUTO-TRANSLATED:15fa6e77]
|
||||
*/
|
||||
API_EXPORT mk_rtsp_get_realm_invoker API_CALL mk_rtsp_get_realm_invoker_clone(const mk_rtsp_get_realm_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtsp_get_realm_invoker_clone_release(const mk_rtsp_get_realm_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////RtspSession::onAuth/////////////////////////////////////////////
|
||||
// RtspSession::onAuth对象的C映射 [AUTO-TRANSLATED:f3a1ebb7]
|
||||
// RtspSession::onAuth对象的C映射
|
||||
typedef struct mk_rtsp_auth_invoker_t *mk_rtsp_auth_invoker;
|
||||
|
||||
@ -321,6 +442,11 @@ typedef struct mk_rtsp_auth_invoker_t *mk_rtsp_auth_invoker;
|
||||
* 执行RtspSession::onAuth
|
||||
* @param encrypted 为true是则表明是md5加密的密码,否则是明文密码, 在请求明文密码时如果提供md5密码者则会导致认证失败
|
||||
* @param pwd_or_md5 明文密码或者md5加密的密码
|
||||
* Execute RtspSession::onAuth
|
||||
* @param encrypted If true, it means that the password is md5 encrypted, otherwise it is plain text password, if you provide md5 password when requesting plain text password, it will cause authentication failure
|
||||
* @param pwd_or_md5 Plain text password or md5 encrypted password
|
||||
|
||||
* [AUTO-TRANSLATED:f7152252]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtsp_auth_invoker_do(const mk_rtsp_auth_invoker ctx,
|
||||
int encrypted,
|
||||
@ -329,15 +455,23 @@ API_EXPORT void API_CALL mk_rtsp_auth_invoker_do(const mk_rtsp_auth_invoker ctx,
|
||||
/**
|
||||
* 克隆mk_rtsp_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_rtsp_auth_invoker_do
|
||||
* 如果是同步执行mk_rtsp_auth_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_rtsp_auth_invoker object, by cloning the object to a heap object, you can achieve cross-thread asynchronous execution of mk_rtsp_auth_invoker_do
|
||||
* If you execute mk_rtsp_auth_invoker_do synchronously, then there is no need to clone the object
|
||||
|
||||
* [AUTO-TRANSLATED:505859bd]
|
||||
*/
|
||||
API_EXPORT mk_rtsp_auth_invoker API_CALL mk_rtsp_auth_invoker_clone(const mk_rtsp_auth_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtsp_auth_invoker_clone_release(const mk_rtsp_auth_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////Broadcast::PublishAuthInvoker/////////////////////////////////////////////
|
||||
// Broadcast::PublishAuthInvoker对象的C映射 [AUTO-TRANSLATED:0eb37ee6]
|
||||
// Broadcast::PublishAuthInvoker对象的C映射
|
||||
typedef struct mk_publish_auth_invoker_t *mk_publish_auth_invoker;
|
||||
|
||||
@ -346,6 +480,12 @@ typedef struct mk_publish_auth_invoker_t *mk_publish_auth_invoker;
|
||||
* @param err_msg 为空或null则代表鉴权成功
|
||||
* @param enable_hls 是否允许转换hls
|
||||
* @param enable_mp4 是否运行MP4录制
|
||||
* Execute Broadcast::PublishAuthInvoker
|
||||
* @param err_msg Empty or null means authentication success
|
||||
* @param enable_hls Whether to allow hls conversion
|
||||
* @param enable_mp4 Whether to allow MP4 recording
|
||||
|
||||
* [AUTO-TRANSLATED:ee8fb2b4]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_publish_auth_invoker_do(const mk_publish_auth_invoker ctx,
|
||||
const char *err_msg,
|
||||
@ -357,37 +497,58 @@ API_EXPORT void API_CALL mk_publish_auth_invoker_do2(const mk_publish_auth_invok
|
||||
/**
|
||||
* 克隆mk_publish_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_publish_auth_invoker_do
|
||||
* 如果是同步执行mk_publish_auth_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_publish_auth_invoker object, by cloning the object to a heap object, you can achieve cross-thread asynchronous execution of mk_publish_auth_invoker_do
|
||||
* If you execute mk_publish_auth_invoker_do synchronously, then there is no need to clone the object
|
||||
|
||||
* [AUTO-TRANSLATED:03357111]
|
||||
*/
|
||||
API_EXPORT mk_publish_auth_invoker API_CALL mk_publish_auth_invoker_clone(const mk_publish_auth_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_publish_auth_invoker_clone_release(const mk_publish_auth_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////Broadcast::AuthInvoker/////////////////////////////////////////////
|
||||
// Broadcast::AuthInvoker对象的C映射 [AUTO-TRANSLATED:08f4186e]
|
||||
// Broadcast::AuthInvoker对象的C映射
|
||||
typedef struct mk_auth_invoker_t *mk_auth_invoker;
|
||||
|
||||
/**
|
||||
* 执行Broadcast::AuthInvoker
|
||||
* @param err_msg 为空或null则代表鉴权成功
|
||||
* Execute Broadcast::AuthInvoker
|
||||
* @param err_msg Empty or null means authentication success
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7215fd9a]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_auth_invoker_do(const mk_auth_invoker ctx, const char *err_msg);
|
||||
|
||||
/**
|
||||
* 克隆mk_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_auth_invoker_do
|
||||
* 如果是同步执行mk_auth_invoker_do,那么没必要克隆对象
|
||||
* Clone the mk_auth_invoker object. By cloning the object to a heap object, we can achieve asynchronous execution of mk_auth_invoker_do across threads.
|
||||
* If mk_auth_invoker_do is executed synchronously, there is no need to clone the object.
|
||||
|
||||
* [AUTO-TRANSLATED:2430560d]
|
||||
*/
|
||||
API_EXPORT mk_auth_invoker API_CALL mk_auth_invoker_clone(const mk_auth_invoker ctx);
|
||||
|
||||
/**
|
||||
* 销毁堆上的克隆对象
|
||||
* Destroy the cloned object on the heap.
|
||||
|
||||
* [AUTO-TRANSLATED:16c6a29b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_auth_invoker_clone_release(const mk_auth_invoker ctx);
|
||||
|
||||
///////////////////////////////////////////WebRtcTransport/////////////////////////////////////////////
|
||||
//WebRtcTransport对象的C映射
|
||||
// WebRtcTransport对象的C映射 [AUTO-TRANSLATED:20b208cc]
|
||||
// C mapping of the WebRtcTransport object
|
||||
typedef struct mk_rtc_transport_t *mk_rtc_transport;
|
||||
|
||||
/**
|
||||
@ -397,6 +558,15 @@ typedef struct mk_rtc_transport_t *mk_rtc_transport;
|
||||
* @param ppid 协议id
|
||||
* @param msg 数据
|
||||
* @param len 数据长度
|
||||
* Send rtc data channel
|
||||
* @param ctx Data channel object
|
||||
* @param streamId Stream id
|
||||
* @param ppid Protocol id
|
||||
* @param msg Data
|
||||
* @param len Data length
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:a0ce3c9e]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtc_send_datachannel(const mk_rtc_transport ctx, uint16_t streamId, uint32_t ppid, const char* msg, size_t len);
|
||||
|
||||
|
@ -17,15 +17,21 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 是否为关键帧 [AUTO-TRANSLATED:b999067c]
|
||||
// cpp
|
||||
//是否为关键帧
|
||||
#define MK_FRAME_FLAG_IS_KEY (1 << 0)
|
||||
// 是否为配置帧(sps/pps/vps等) [AUTO-TRANSLATED:cf504832]
|
||||
// 是否为配置帧(sps/pps/vps等)
|
||||
#define MK_FRAME_FLAG_IS_CONFIG (1 << 1)
|
||||
// 是否可丢弃的帧(sei/aud) [AUTO-TRANSLATED:6481fe69]
|
||||
// 是否可丢弃的帧(sei/aud)
|
||||
#define MK_FRAME_FLAG_DROP_ABLE (1 << 2)
|
||||
// 是否不可单独解码的帧(多slice的非vcl帧) [AUTO-TRANSLATED:cb4da662]
|
||||
// 是否不可单独解码的帧(多slice的非vcl帧)
|
||||
#define MK_FRAME_FLAG_NOT_DECODE_ABLE (1 << 3)
|
||||
|
||||
// codec id常量定义 [AUTO-TRANSLATED:dbc838b6]
|
||||
// codec id常量定义
|
||||
API_EXPORT extern const int MKCodecH264;
|
||||
API_EXPORT extern const int MKCodecH265;
|
||||
@ -41,6 +47,7 @@ API_EXPORT extern const int MKCodecJPEG;
|
||||
|
||||
typedef struct mk_frame_t *mk_frame;
|
||||
|
||||
// 用户自定义free回调函数 [AUTO-TRANSLATED:dc96ff2d]
|
||||
// 用户自定义free回调函数
|
||||
typedef void(API_CALL *on_mk_frame_data_release)(void *user_data, char *ptr);
|
||||
|
||||
@ -54,6 +61,17 @@ typedef void(API_CALL *on_mk_frame_data_release)(void *user_data, char *ptr);
|
||||
* @param cb data指针free释放回调, 如果为空,内部会拷贝数据
|
||||
* @param user_data data指针free释放回调用户指针
|
||||
* @return frame对象引用
|
||||
* Create a frame object and return its reference.
|
||||
* @param codec_id Encoding and decoding type, please refer to MKCodecXXX definition.
|
||||
* @param dts Decoding timestamp, in milliseconds.
|
||||
* @param pts Display timestamp, in milliseconds.
|
||||
* @param data Single frame data.
|
||||
* @param size Single frame data length.
|
||||
* @param cb data pointer free release callback, if empty, the data will be copied internally.
|
||||
* @param user_data data pointer free release callback user pointer.
|
||||
* @return frame object reference.
|
||||
|
||||
* [AUTO-TRANSLATED:0481221b]
|
||||
*/
|
||||
API_EXPORT mk_frame API_CALL mk_frame_create(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
|
||||
on_mk_frame_data_release cb, void *user_data);
|
||||
@ -62,6 +80,10 @@ API_EXPORT mk_frame API_CALL mk_frame_create2(int codec_id, uint64_t dts, uint64
|
||||
/**
|
||||
* 减引用frame对象
|
||||
* @param frame 帧对象引用
|
||||
* Decrement the reference of the frame object.
|
||||
* @param frame Frame object reference.
|
||||
|
||||
* [AUTO-TRANSLATED:53b5a750]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_unref(mk_frame frame);
|
||||
|
||||
@ -69,51 +91,83 @@ API_EXPORT void API_CALL mk_frame_unref(mk_frame frame);
|
||||
* 引用frame对象
|
||||
* @param frame 被引用的frame对象
|
||||
* @return 新的对象引用
|
||||
* Reference the frame object.
|
||||
* @param frame The referenced frame object.
|
||||
* @return New object reference.
|
||||
|
||||
* [AUTO-TRANSLATED:f772813d]
|
||||
*/
|
||||
API_EXPORT mk_frame API_CALL mk_frame_ref(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取frame 编码codec类型,请参考MKCodecXXX定义
|
||||
* Get the frame encoding codec type, please refer to MKCodecXXX definition.
|
||||
|
||||
* [AUTO-TRANSLATED:b3a34bb8]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_frame_codec_id(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧编码codec名称
|
||||
* Get the frame encoding codec name.
|
||||
|
||||
* [AUTO-TRANSLATED:6c3129d7]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_frame_codec_name(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 帧是否为视频
|
||||
* Whether the frame is video.
|
||||
|
||||
* [AUTO-TRANSLATED:c43dbd4e]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_frame_is_video(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧数据指针
|
||||
* Get the frame data pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:bf454f3b]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_frame_get_data(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧数据指针长度
|
||||
* Get the length of the frame data pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:8a76acf2]
|
||||
*/
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_size(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 返回帧数据前缀长度,譬如H264/H265前缀一般是0x00 00 00 01,那么本函数返回4
|
||||
* Return the length of the frame data prefix, for example, the H264/H265 prefix is generally 0x00 00 00 01, then this function returns 4.
|
||||
|
||||
* [AUTO-TRANSLATED:352c7cfc]
|
||||
*/
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_prefix_size(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取解码时间戳,单位毫秒
|
||||
* Get the decoding timestamp, in milliseconds.
|
||||
|
||||
* [AUTO-TRANSLATED:049f1339]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_frame_get_dts(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取显示时间戳,单位毫秒
|
||||
* Get the display timestamp, in milliseconds.
|
||||
|
||||
* [AUTO-TRANSLATED:4ab081a7]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_frame_get_pts(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧flag,请参考 MK_FRAME_FLAG
|
||||
* Get the frame flag, please refer to MK_FRAME_FLAG.
|
||||
|
||||
* [AUTO-TRANSLATED:6fdf971c]
|
||||
*/
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_flags(mk_frame frame);
|
||||
|
||||
@ -126,18 +180,31 @@ typedef struct mk_frame_merger_t *mk_frame_merger;
|
||||
* 创建帧合并器
|
||||
* @param type 起始头类型,0: none, 1: h264_prefix/AnnexB(0x 00 00 00 01), 2: mp4_nal_size(avcC)
|
||||
* @return 帧合并器
|
||||
* Create a frame merger.
|
||||
* @param type Starting header type, 0: none, 1: h264_prefix/AnnexB(0x 00 00 00 01), 2: mp4_nal_size(avcC)
|
||||
* @return Frame merger.
|
||||
|
||||
* [AUTO-TRANSLATED:385eedd7]
|
||||
*/
|
||||
API_EXPORT mk_frame_merger API_CALL mk_frame_merger_create(int type);
|
||||
|
||||
/**
|
||||
* 销毁帧合并器
|
||||
* @param ctx 对象指针
|
||||
* Destroy the frame merger.
|
||||
* @param ctx Object pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:0c9aad7b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_merger_release(mk_frame_merger ctx);
|
||||
|
||||
/**
|
||||
* 清空merger对象缓冲,方便复用
|
||||
* @param ctx 对象指针
|
||||
* Clear the merger object buffer for reuse.
|
||||
* @param ctx Object pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:6b1d2209]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_merger_clear(mk_frame_merger ctx);
|
||||
|
||||
@ -148,6 +215,14 @@ API_EXPORT void API_CALL mk_frame_merger_clear(mk_frame_merger ctx);
|
||||
* @param pts 显示时间戳
|
||||
* @param buffer 合并后数据buffer对象
|
||||
* @param have_key_frame 合并后数据中是否包含关键帧
|
||||
* Frame merging callback function.
|
||||
* @param user_data User data pointer.
|
||||
* @param dts Decoding timestamp.
|
||||
* @param pts Display timestamp.
|
||||
* @param buffer Merged data buffer object.
|
||||
* @param have_key_frame Whether the merged data contains a key frame.
|
||||
|
||||
* [AUTO-TRANSLATED:ff78df4f]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_frame_merger)(void *user_data, uint64_t dts, uint64_t pts, mk_buffer buffer, int have_key_frame);
|
||||
|
||||
@ -157,12 +232,23 @@ typedef void(API_CALL *on_mk_frame_merger)(void *user_data, uint64_t dts, uint64
|
||||
* @param frame 帧数据
|
||||
* @param cb 帧合并回调函数
|
||||
* @param user_data 帧合并回调函数用户数据指针
|
||||
* Input frame to the merger object and merge.
|
||||
* @param ctx Object pointer.
|
||||
* @param frame Frame data.
|
||||
* @param cb Frame merging callback function.
|
||||
* @param user_data Frame merging callback function user data pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:83aa1436]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_merger_input(mk_frame_merger ctx, mk_frame frame, on_mk_frame_merger cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 强制flush merger对象缓冲,调用此api前需要确保先调用mk_frame_merger_input函数并且回调参数有效
|
||||
* @param ctx 对象指针
|
||||
* Force flush the merger object buffer. Before calling this API, make sure to call the mk_frame_merger_input function first and the callback parameters are valid.
|
||||
* @param ctx Object pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:42bb104c]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_merger_flush(mk_frame_merger ctx);
|
||||
|
||||
@ -178,6 +264,15 @@ typedef struct mk_mpeg_muxer_t *mk_mpeg_muxer;
|
||||
* @param size 帧数据长度
|
||||
* @param timestamp 时间戳
|
||||
* @param key_pos 是否关键帧
|
||||
* mpeg-ps/ts packer output callback function.
|
||||
* @param user_data User data pointer set during callback.
|
||||
* @param muxer Object.
|
||||
* @param frame Frame data.
|
||||
* @param size Frame data length.
|
||||
* @param timestamp Timestamp.
|
||||
* @param key_pos Whether it is a key frame.
|
||||
|
||||
* [AUTO-TRANSLATED:14c103a2]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_mpeg_muxer_frame)(void *user_data, mk_mpeg_muxer muxer, const char *frame, size_t size, uint64_t timestamp, int key_pos);
|
||||
|
||||
@ -187,12 +282,23 @@ typedef void(API_CALL *on_mk_mpeg_muxer_frame)(void *user_data, mk_mpeg_muxer mu
|
||||
* @param user_data 回调用户数据指针
|
||||
* @param is_ps 是否是ps
|
||||
* @return 打包器对象
|
||||
* mpeg-ps/ts packer.
|
||||
* @param cb Packing callback function.
|
||||
* @param user_data Callback user data pointer.
|
||||
* @param is_ps Whether it is ps.
|
||||
* @return Packer object.
|
||||
|
||||
* [AUTO-TRANSLATED:6526b871]
|
||||
*/
|
||||
API_EXPORT mk_mpeg_muxer API_CALL mk_mpeg_muxer_create(on_mk_mpeg_muxer_frame cb, void *user_data, int is_ps);
|
||||
|
||||
/**
|
||||
* 删除mpeg-ps/ts 打包器
|
||||
* @param ctx 打包器
|
||||
* Delete the mpeg-ps/ts packer.
|
||||
* @param ctx Packer.
|
||||
|
||||
* [AUTO-TRANSLATED:0b533391]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_mpeg_muxer_release(mk_mpeg_muxer ctx);
|
||||
|
||||
@ -200,6 +306,11 @@ API_EXPORT void API_CALL mk_mpeg_muxer_release(mk_mpeg_muxer ctx);
|
||||
* 添加音视频track
|
||||
* @param ctx mk_mpeg_muxer对象
|
||||
* @param track mk_track对象,音视频轨道
|
||||
* Add audio/video track.
|
||||
* @param ctx mk_mpeg_muxer object.
|
||||
* @param track mk_track object, audio/video track.
|
||||
|
||||
* [AUTO-TRANSLATED:f2082619]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_mpeg_muxer_init_track(mk_mpeg_muxer ctx, void* track);
|
||||
|
||||
@ -208,6 +319,12 @@ API_EXPORT void API_CALL mk_mpeg_muxer_init_track(mk_mpeg_muxer ctx, void* track
|
||||
* 在单track(只有音频或视频)时,因为ZLMediaKit不知道后续是否还要添加track,所以会多等待3秒钟
|
||||
* 如果产生的流是单Track类型,请调用此函数以便加快流生成速度,当然不调用该函数,影响也不大(会多等待3秒)
|
||||
* @param ctx 对象指针
|
||||
* Call this function after the track is initialized.
|
||||
* In the case of a single track (only audio or video), because ZLMediaKit does not know whether to add more tracks later, it will wait for an additional 3 seconds.
|
||||
* If the generated stream is a single Track type, please call this function to speed up the stream generation. Of course, if you don't call this function, the impact is not big (it will wait for an additional 3 seconds).
|
||||
* @param ctx Object pointer.
|
||||
|
||||
* [AUTO-TRANSLATED:f40d41cb]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_mpeg_muxer_init_complete(mk_mpeg_muxer ctx);
|
||||
|
||||
@ -216,6 +333,13 @@ API_EXPORT void API_CALL mk_mpeg_muxer_init_complete(mk_mpeg_muxer ctx);
|
||||
* @param ctx mk_mpeg_muxer对象
|
||||
* @param frame 帧对象
|
||||
* @return 1代表成功,0失败
|
||||
* Input frame object.
|
||||
* @param ctx mk_mpeg_muxer object.
|
||||
* @param frame Frame object.
|
||||
* @return 1 means success, 0 means failure.
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:46523906]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_mpeg_muxer_input_frame(mk_mpeg_muxer ctx, mk_frame frame);
|
||||
|
||||
|
@ -25,6 +25,13 @@ typedef struct mk_h264_splitter_t *mk_h264_splitter;
|
||||
* @param splitter 对象
|
||||
* @param frame 帧数据
|
||||
* @param size 帧数据长度
|
||||
* h264 frame splitter output callback function
|
||||
* @param user_data user data pointer set when setting the callback
|
||||
* @param splitter object
|
||||
* @param frame frame data
|
||||
* @param size frame data length
|
||||
|
||||
* [AUTO-TRANSLATED:3e4e4dfa]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_h264_splitter_frame)(void *user_data, mk_h264_splitter splitter, const char *frame, int size);
|
||||
|
||||
@ -34,6 +41,13 @@ typedef void(API_CALL *on_mk_h264_splitter_frame)(void *user_data, mk_h264_split
|
||||
* @param user_data 回调用户数据指针
|
||||
* @param is_h265 是否是265
|
||||
* @return 分帧器对象
|
||||
* Create h264 frame splitter
|
||||
* @param cb frame splitting callback function
|
||||
* @param user_data callback user data pointer
|
||||
* @param is_h265 whether it is 265
|
||||
* @return frame splitter object
|
||||
|
||||
* [AUTO-TRANSLATED:6e06f68d]
|
||||
*/
|
||||
API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create(on_mk_h264_splitter_frame cb, void *user_data, int is_h265);
|
||||
API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create2(on_mk_h264_splitter_frame cb, void *user_data, on_user_data_free user_data_free, int is_h265);
|
||||
@ -41,6 +55,10 @@ API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create2(on_mk_h264_splitte
|
||||
/**
|
||||
* 删除h264分帧器
|
||||
* @param ctx 分帧器
|
||||
* Delete h264 frame splitter
|
||||
* @param ctx frame splitter
|
||||
|
||||
* [AUTO-TRANSLATED:e69bb6dd]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_h264_splitter_release(mk_h264_splitter ctx);
|
||||
|
||||
@ -49,6 +67,13 @@ API_EXPORT void API_CALL mk_h264_splitter_release(mk_h264_splitter ctx);
|
||||
* @param ctx 分帧器
|
||||
* @param data h264/h265数据
|
||||
* @param size 数据长度
|
||||
* Input data and split frames
|
||||
* @param ctx frame splitter
|
||||
* @param data h264/h265 data
|
||||
* @param size data length
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:c6b93aed]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_h264_splitter_input_data(mk_h264_splitter ctx, const char *data, int size);
|
||||
|
||||
|
@ -27,18 +27,32 @@ typedef struct mk_http_downloader_t *mk_http_downloader;
|
||||
* @param code 错误代码,0代表成功
|
||||
* @param err_msg 错误提示
|
||||
* @param file_path 文件保存路径
|
||||
* @param user_data User data pointer
|
||||
* @param code Error code, 0 represents success
|
||||
* @param err_msg Error message
|
||||
* @param file_path File save path
|
||||
|
||||
* [AUTO-TRANSLATED:8f8ed7ef]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_download_complete)(void *user_data, int code, const char *err_msg, const char *file_path);
|
||||
|
||||
/**
|
||||
* 创建http[s]下载器
|
||||
* @return 下载器指针
|
||||
* Create http[s] downloader
|
||||
* @return Downloader pointer
|
||||
|
||||
* [AUTO-TRANSLATED:93112194]
|
||||
*/
|
||||
API_EXPORT mk_http_downloader API_CALL mk_http_downloader_create();
|
||||
|
||||
/**
|
||||
* 销毁http[s]下载器
|
||||
* @param ctx 下载器指针
|
||||
* Destroy http[s] downloader
|
||||
* @param ctx Downloader pointer
|
||||
|
||||
* [AUTO-TRANSLATED:8378a5a7]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_downloader_release(mk_http_downloader ctx);
|
||||
|
||||
@ -49,6 +63,14 @@ API_EXPORT void API_CALL mk_http_downloader_release(mk_http_downloader ctx);
|
||||
* @param file 文件保存路径
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
* Start http[s] download
|
||||
* @param ctx Downloader pointer
|
||||
* @param url http[s] download url
|
||||
* @param file File save path
|
||||
* @param cb Callback function
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:8a2acf02]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_downloader_start(mk_http_downloader ctx, const char *url, const char *file, on_mk_download_complete cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_http_downloader_start2(mk_http_downloader ctx, const char *url, const char *file, on_mk_download_complete cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -66,16 +88,33 @@ typedef struct mk_http_requester_t *mk_http_requester;
|
||||
* @param user_data 用户数据指针
|
||||
* @param code 错误代码,0代表成功
|
||||
* @param err_msg 错误提示
|
||||
* Http request result callback
|
||||
* When code == 0, it means that the current http session is complete (http response has been received)
|
||||
* Users should get the mk_http_requester object through user_data
|
||||
* Then get the relevant response data through functions such as mk_http_requester_get_response
|
||||
* At the end of the callback, the object should be destroyed by calling the mk_http_requester_release function
|
||||
* Or reuse the object after calling the mk_http_requester_clear function
|
||||
* @param user_data User data pointer
|
||||
* @param code Error code, 0 represents success
|
||||
* @param err_msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:d24408ce]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_http_requester_complete)(void *user_data, int code, const char *err_msg);
|
||||
|
||||
/**
|
||||
* 创建HttpRequester
|
||||
* Create HttpRequester
|
||||
|
||||
* [AUTO-TRANSLATED:fa182fbc]
|
||||
*/
|
||||
API_EXPORT mk_http_requester API_CALL mk_http_requester_create();
|
||||
|
||||
/**
|
||||
* 在复用mk_http_requester对象时才需要用到此方法
|
||||
* This method is only needed when reusing the mk_http_requester object
|
||||
|
||||
* [AUTO-TRANSLATED:6854d97f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_clear(mk_http_requester ctx);
|
||||
|
||||
@ -83,17 +122,29 @@ API_EXPORT void API_CALL mk_http_requester_clear(mk_http_requester ctx);
|
||||
* 销毁HttpRequester
|
||||
* 如果调用了mk_http_requester_start函数且正在等待http回复,
|
||||
* 也可以调用mk_http_requester_release方法取消本次http请求
|
||||
* Destroy HttpRequester
|
||||
* If the mk_http_requester_start function is called and is waiting for the http response,
|
||||
* You can also call the mk_http_requester_release method to cancel the current http request
|
||||
|
||||
* [AUTO-TRANSLATED:5f533e28]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_release(mk_http_requester ctx);
|
||||
|
||||
/**
|
||||
* 设置HTTP方法,譬如GET/POST
|
||||
* Set HTTP method, such as GET/POST
|
||||
|
||||
* [AUTO-TRANSLATED:d4b641f1]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_set_method(mk_http_requester ctx,const char *method);
|
||||
|
||||
/**
|
||||
* 批量设置设置HTTP头
|
||||
* @param header 譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
|
||||
* Batch set HTTP headers
|
||||
* @param header For example, {"Content-Type","text/html",NULL} must end with NULL
|
||||
|
||||
* [AUTO-TRANSLATED:65124347]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_set_header(mk_http_requester ctx, const char *header[]);
|
||||
|
||||
@ -102,18 +153,32 @@ API_EXPORT void API_CALL mk_http_requester_set_header(mk_http_requester ctx, con
|
||||
* @param key 譬如Content-Type
|
||||
* @param value 譬如 text/html
|
||||
* @param force 如果已经存在该key,是否强制替换
|
||||
* Add HTTP header
|
||||
* @param key For example, Content-Type
|
||||
* @param value For example, text/html
|
||||
* @param force If the key already exists, whether to force replacement
|
||||
|
||||
* [AUTO-TRANSLATED:79d32682]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_add_header(mk_http_requester ctx,const char *key,const char *value,int force);
|
||||
|
||||
/**
|
||||
* 设置消息体,
|
||||
* @param body mk_http_body对象,通过mk_http_body_from_string等函数生成,使用完毕后请调用mk_http_body_release释放之
|
||||
* Set message body,
|
||||
* @param body mk_http_body object, generated by functions such as mk_http_body_from_string, please call mk_http_body_release to release it after use
|
||||
|
||||
* [AUTO-TRANSLATED:85d0f139]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_set_body(mk_http_requester ctx, mk_http_body body);
|
||||
|
||||
/**
|
||||
* 在收到HTTP回复后可调用该方法获取状态码
|
||||
* @return 譬如 200 OK
|
||||
* You can call this method to get the status code after receiving the HTTP response
|
||||
* @return For example, 200 OK
|
||||
|
||||
* [AUTO-TRANSLATED:7757b21a]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_http_requester_get_response_status(mk_http_requester ctx);
|
||||
|
||||
@ -121,6 +186,11 @@ API_EXPORT const char* API_CALL mk_http_requester_get_response_status(mk_http_re
|
||||
* 在收到HTTP回复后可调用该方法获取响应HTTP头
|
||||
* @param key HTTP头键名
|
||||
* @return HTTP头键值
|
||||
* You can call this method to get the response HTTP header after receiving the HTTP response
|
||||
* @param key HTTP header key name
|
||||
* @return HTTP header key value
|
||||
|
||||
* [AUTO-TRANSLATED:10f8ae74]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_http_requester_get_response_header(mk_http_requester ctx,const char *key);
|
||||
|
||||
@ -128,12 +198,21 @@ API_EXPORT const char* API_CALL mk_http_requester_get_response_header(mk_http_re
|
||||
* 在收到HTTP回复后可调用该方法获取响应HTTP body
|
||||
* @param length 返回body长度,可以为null
|
||||
* @return body指针
|
||||
* You can call this method to get the response HTTP body after receiving the HTTP response
|
||||
* @param length Return body length, can be null
|
||||
* @return Body pointer
|
||||
|
||||
* [AUTO-TRANSLATED:764dbb38]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_http_requester_get_response_body(mk_http_requester ctx, size_t *length);
|
||||
|
||||
/**
|
||||
* 在收到HTTP回复后可调用该方法获取响应
|
||||
* @return 响应对象
|
||||
* You can call this method to get the response after receiving the HTTP response
|
||||
* @return Response object
|
||||
|
||||
* [AUTO-TRANSLATED:3800b175]
|
||||
*/
|
||||
API_EXPORT mk_parser API_CALL mk_http_requester_get_response(mk_http_requester ctx);
|
||||
|
||||
@ -141,6 +220,11 @@ API_EXPORT mk_parser API_CALL mk_http_requester_get_response(mk_http_requester c
|
||||
* 设置回调函数
|
||||
* @param cb 回调函数,不能为空
|
||||
* @param user_data 用户数据指针
|
||||
* Set callback function
|
||||
* @param cb Callback function, cannot be empty
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:f04412b8]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_set_cb(mk_http_requester ctx,on_mk_http_requester_complete cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_http_requester_set_cb2(mk_http_requester ctx,on_mk_http_requester_complete cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -149,6 +233,11 @@ API_EXPORT void API_CALL mk_http_requester_set_cb2(mk_http_requester ctx,on_mk_h
|
||||
* 开始url请求
|
||||
* @param url 请求url,支持http/https
|
||||
* @param timeout_second 最大超时时间
|
||||
* Start url request
|
||||
* @param url Request url, supports http/https
|
||||
* @param timeout_second Maximum timeout time
|
||||
|
||||
* [AUTO-TRANSLATED:36986fec]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_http_requester_start(mk_http_requester ctx,const char *url, float timeout_second);
|
||||
|
||||
|
@ -33,6 +33,16 @@ typedef struct mk_media_t *mk_media;
|
||||
* @param hls_enabled 是否生成hls
|
||||
* @param mp4_enabled 是否生成mp4
|
||||
* @return 对象指针
|
||||
* Create a media source
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name, recommended as live
|
||||
* @param stream Stream id, such as camera
|
||||
* @param duration Duration (in seconds), 0 for live broadcast
|
||||
* @param hls_enabled Whether to generate hls
|
||||
* @param mp4_enabled Whether to generate mp4
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:b5124a1e]
|
||||
*/
|
||||
API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app, const char *stream,
|
||||
float duration, int hls_enabled, int mp4_enabled);
|
||||
@ -45,12 +55,25 @@ API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app,
|
||||
* @param duration 时长(单位秒),直播则为0
|
||||
* @param option ProtocolOption相关配置
|
||||
* @return 对象指针
|
||||
* Create a media source
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name, recommended as live
|
||||
* @param stream Stream id, such as camera
|
||||
* @param duration Duration (in seconds), 0 for live broadcast
|
||||
* @param option ProtocolOption related configuration
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:870d86b0]
|
||||
*/
|
||||
API_EXPORT mk_media API_CALL mk_media_create2(const char *vhost, const char *app, const char *stream, float duration, mk_ini option);
|
||||
|
||||
/**
|
||||
* 销毁媒体源
|
||||
* @param ctx 对象指针
|
||||
* Destroy the media source
|
||||
* @param ctx Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:a63ad166]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_release(mk_media ctx);
|
||||
|
||||
@ -58,6 +81,11 @@ API_EXPORT void API_CALL mk_media_release(mk_media ctx);
|
||||
* 添加音视频track
|
||||
* @param ctx mk_media对象
|
||||
* @param track mk_track对象,音视频轨道
|
||||
* Add audio and video tracks
|
||||
* @param ctx mk_media object
|
||||
* @param track mk_track object, audio and video track
|
||||
|
||||
* [AUTO-TRANSLATED:0e4ebe8d]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_init_track(mk_media ctx, mk_track track);
|
||||
|
||||
@ -73,6 +101,19 @@ API_EXPORT void API_CALL mk_media_init_track(mk_media ctx, mk_track track);
|
||||
* @param height 视频高度
|
||||
* @param fps 视频fps
|
||||
* @return 1代表成功,0失败
|
||||
* Add video track, please use mk_media_init_track method
|
||||
* @param ctx Object pointer
|
||||
* @param codec_id 0:CodecH264/1:CodecH265
|
||||
* @param width Video width; Valid only during encoding
|
||||
* @param height Video height; Valid only during encoding
|
||||
* @param fps Video fps; Valid only during encoding
|
||||
* @param bit_rate Video bitrate, unit bps; Valid only during encoding
|
||||
* @param width Video width
|
||||
* @param height Video height
|
||||
* @param fps Video fps
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:c6944851]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int width, int height, float fps, int bit_rate);
|
||||
|
||||
@ -84,6 +125,15 @@ API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int widt
|
||||
* @param sample_bit 采样位数,只支持16
|
||||
* @param sample_rate 采样率
|
||||
* @return 1代表成功,0失败
|
||||
* Add audio track, please use mk_media_init_track method
|
||||
* @param ctx Object pointer
|
||||
* @param codec_id 2:CodecAAC/3:CodecG711A/4:CodecG711U/5:OPUS
|
||||
* @param channel Number of channels
|
||||
* @param sample_bit Sampling bit, only supports 16
|
||||
* @param sample_rate Sampling rate
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:5c5c7c7a]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_init_audio(mk_media ctx, int codec_id, int sample_rate, int channels, int sample_bit);
|
||||
|
||||
@ -92,6 +142,12 @@ API_EXPORT int API_CALL mk_media_init_audio(mk_media ctx, int codec_id, int samp
|
||||
* 在单track(只有音频或视频)时,因为ZLMediaKit不知道后续是否还要添加track,所以会多等待3秒钟
|
||||
* 如果产生的流是单Track类型,请调用此函数以便加快流生成速度,当然不调用该函数,影响也不大(会多等待3秒)
|
||||
* @param ctx 对象指针
|
||||
* Call this function after h264/h265/aac initialization,
|
||||
* In single track (only audio or video), because ZLMediaKit does not know whether to add more tracks later, it will wait for 3 seconds.
|
||||
* If the generated stream is a single Track type, please call this function to speed up the stream generation speed. Of course, if you do not call this function, the impact is not big (it will wait for 3 seconds).
|
||||
* @param ctx Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:cd2bee12]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_init_complete(mk_media ctx);
|
||||
|
||||
@ -100,6 +156,12 @@ API_EXPORT void API_CALL mk_media_init_complete(mk_media ctx);
|
||||
* @param ctx mk_media对象
|
||||
* @param frame 帧对象
|
||||
* @return 1代表成功,0失败
|
||||
* Input frame object
|
||||
* @param ctx mk_media object
|
||||
* @param frame Frame object
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:9f6ca231]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_frame(mk_media ctx, mk_frame frame);
|
||||
|
||||
@ -111,6 +173,15 @@ API_EXPORT int API_CALL mk_media_input_frame(mk_media ctx, mk_frame frame);
|
||||
* @param dts 解码时间戳,单位毫秒
|
||||
* @param pts 播放时间戳,单位毫秒
|
||||
* @return 1代表成功,0失败
|
||||
* Input single frame H264 video, the starting byte of the frame can be 00 00 01, 00 00 00 01, please use mk_media_input_frame method
|
||||
* @param ctx Object pointer
|
||||
* @param data Single frame H264 data
|
||||
* @param len Number of bytes of single frame H264 data
|
||||
* @param dts Decode timestamp, unit milliseconds
|
||||
* @param pts Play timestamp, unit milliseconds
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:3b96ace8]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_h264(mk_media ctx, const void *data, int len, uint64_t dts, uint64_t pts);
|
||||
|
||||
@ -122,6 +193,15 @@ API_EXPORT int API_CALL mk_media_input_h264(mk_media ctx, const void *data, int
|
||||
* @param dts 解码时间戳,单位毫秒
|
||||
* @param pts 播放时间戳,单位毫秒
|
||||
* @return 1代表成功,0失败
|
||||
* Input single frame H265 video, the starting byte of the frame can be 00 00 01, 00 00 00 01, please use mk_media_input_frame method
|
||||
* @param ctx Object pointer
|
||||
* @param data Single frame H265 data
|
||||
* @param len Number of bytes of single frame H265 data
|
||||
* @param dts Decode timestamp, unit milliseconds
|
||||
* @param pts Play timestamp, unit milliseconds
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:884739ba]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_h265(mk_media ctx, const void *data, int len, uint64_t dts, uint64_t pts);
|
||||
|
||||
@ -131,6 +211,13 @@ API_EXPORT int API_CALL mk_media_input_h265(mk_media ctx, const void *data, int
|
||||
* @param yuv yuv420p数据
|
||||
* @param linesize yuv420p linesize
|
||||
* @param cts 视频采集时间戳,单位毫秒
|
||||
* Input YUV video data
|
||||
* @param ctx Object pointer
|
||||
* @param yuv yuv420p data
|
||||
* @param linesize yuv420p linesize
|
||||
* @param cts Video capture timestamp, unit milliseconds
|
||||
|
||||
* [AUTO-TRANSLATED:9c97805c]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_input_yuv(mk_media ctx, const char *yuv[3], int linesize[3], uint64_t cts);
|
||||
|
||||
@ -142,6 +229,15 @@ API_EXPORT void API_CALL mk_media_input_yuv(mk_media ctx, const char *yuv[3], in
|
||||
* @param dts 时间戳,毫秒
|
||||
* @param adts adts头,可以为null
|
||||
* @return 1代表成功,0失败
|
||||
* Input single frame AAC audio (specify adts header separately), please use mk_media_input_frame method
|
||||
* @param ctx Object pointer
|
||||
* @param data Single frame AAC data without adts header, adts header 7 bytes
|
||||
* @param len Number of bytes of single frame AAC data
|
||||
* @param dts Timestamp, milliseconds
|
||||
* @param adts adts header, can be null
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:11e0503d]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int len, uint64_t dts, void *adts);
|
||||
|
||||
@ -152,6 +248,14 @@ API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int l
|
||||
* @param len 单帧PCM数据字节数
|
||||
* @param dts 时间戳,毫秒
|
||||
* @return 1代表成功,0失败
|
||||
* Input single frame PCM audio, this function is valid only when ENABLE_FAAC is compiled
|
||||
* @param ctx Object pointer
|
||||
* @param data Single frame PCM data
|
||||
* @param len Number of bytes of single frame PCM data
|
||||
* @param dts Timestamp, milliseconds
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:70f7488b]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, uint64_t pts);
|
||||
|
||||
@ -162,6 +266,14 @@ API_EXPORT int API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, ui
|
||||
* @param len 单帧音频数据字节数
|
||||
* @param dts 时间戳,毫秒
|
||||
* @return 1代表成功,0失败
|
||||
* Input single frame OPUS/G711 audio frame, please use mk_media_input_frame method
|
||||
* @param ctx Object pointer
|
||||
* @param data Single frame audio data
|
||||
* @param len Number of bytes of single frame audio data
|
||||
* @param dts Timestamp, milliseconds
|
||||
* @return 1 for success, 0 for failure
|
||||
|
||||
* [AUTO-TRANSLATED:4ffeabd6]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_input_audio(mk_media ctx, const void* data, int len, uint64_t dts);
|
||||
|
||||
@ -171,6 +283,13 @@ API_EXPORT int API_CALL mk_media_input_audio(mk_media ctx, const void* data, int
|
||||
* 你应该通过该事件调用mk_media_release函数并且释放其他资源
|
||||
* 如果你不调用mk_media_release函数,那么MediaSource.close()操作将无效
|
||||
* @param user_data 用户数据指针,通过mk_media_set_on_close函数设置
|
||||
* MediaSource.close() callback event
|
||||
* When you choose to close an associated MediaSource, it will eventually trigger this callback
|
||||
* You should call mk_media_release function and release other resources through this event
|
||||
* If you do not call mk_media_release function, then the MediaSource.close() operation will be invalid
|
||||
* @param user_data User data pointer, set by mk_media_set_on_close function
|
||||
|
||||
* [AUTO-TRANSLATED:20191b2d]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_media_close)(void *user_data);
|
||||
|
||||
@ -181,6 +300,14 @@ typedef void(API_CALL *on_mk_media_close)(void *user_data);
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Listen to MediaSource.close() event
|
||||
* When you choose to close an associated MediaSource, it will eventually trigger this callback
|
||||
* You should call mk_media_release function and release other resources through this event
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:35d9db20]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_set_on_close2(mk_media ctx, on_mk_media_close cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -190,6 +317,12 @@ API_EXPORT void API_CALL mk_media_set_on_close2(mk_media ctx, on_mk_media_close
|
||||
* @param user_data 用户数据指针,通过mk_media_set_on_seek设置
|
||||
* @param stamp_ms seek至的时间轴位置,单位毫秒
|
||||
* @return 1代表将处理seek请求,0代表忽略该请求
|
||||
* Triggered when the client receives a seek request
|
||||
* @param user_data User data pointer, set by mk_media_set_on_seek
|
||||
* @param stamp_ms Seek to the timeline position, unit milliseconds
|
||||
* @return 1 means the seek request will be processed, 0 means the request will be ignored
|
||||
|
||||
* [AUTO-TRANSLATED:c3301852]
|
||||
*/
|
||||
typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms);
|
||||
|
||||
@ -197,6 +330,11 @@ typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms);
|
||||
* 收到客户端的pause或resume请求时触发该回调
|
||||
* @param user_data 用户数据指针,通过mk_media_set_on_pause设置
|
||||
* @param pause 1:暂停, 0: 恢复
|
||||
* Triggered when the client receives a pause or resume request
|
||||
* @param user_data User data pointer, set by mk_media_set_on_pause
|
||||
* @param pause 1: pause, 0: resume
|
||||
|
||||
* [AUTO-TRANSLATED:4f8aa828]
|
||||
*/
|
||||
typedef int(API_CALL* on_mk_media_pause)(void* user_data, int pause);
|
||||
|
||||
@ -204,6 +342,11 @@ typedef int(API_CALL* on_mk_media_pause)(void* user_data, int pause);
|
||||
* 收到客户端的speed请求时触发该回调
|
||||
* @param user_data 用户数据指针,通过mk_media_set_on_pause设置
|
||||
* @param speed 0.5 1.0 2.0
|
||||
* Triggered when the client receives a speed request
|
||||
* @param user_data User data pointer, set by mk_media_set_on_pause
|
||||
* @param speed 0.5 1.0 2.0
|
||||
|
||||
* [AUTO-TRANSLATED:51bd090d]
|
||||
*/
|
||||
typedef int(API_CALL* on_mk_media_speed)(void* user_data, float speed);
|
||||
|
||||
@ -212,6 +355,12 @@ typedef int(API_CALL* on_mk_media_speed)(void* user_data, float speed);
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Listen to player seek request event
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:50c723d0]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_set_on_seek2(mk_media ctx, on_mk_media_seek cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -221,6 +370,12 @@ API_EXPORT void API_CALL mk_media_set_on_seek2(mk_media ctx, on_mk_media_seek cb
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Listen to player pause request event
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:bd6e9068]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_set_on_pause(mk_media ctx, on_mk_media_pause cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_set_on_pause2(mk_media ctx, on_mk_media_pause cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -230,6 +385,12 @@ API_EXPORT void API_CALL mk_media_set_on_pause2(mk_media ctx, on_mk_media_pause
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Listen to player pause request event
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:bd6e9068]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_set_on_speed(mk_media ctx, on_mk_media_speed cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_set_on_speed2(mk_media ctx, on_mk_media_speed cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -238,6 +399,11 @@ API_EXPORT void API_CALL mk_media_set_on_speed2(mk_media ctx, on_mk_media_speed
|
||||
* 获取总的观看人数
|
||||
* @param ctx 对象指针
|
||||
* @return 观看人数
|
||||
* Get the total number of viewers
|
||||
* @param ctx Object pointer
|
||||
* @return Number of viewers
|
||||
|
||||
* [AUTO-TRANSLATED:56635caf]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx);
|
||||
|
||||
@ -246,6 +412,12 @@ API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx);
|
||||
* @param user_data 设置回调时的用户数据指针
|
||||
* @param sender 生成的MediaSource对象
|
||||
* @param regist 1为注册事件,0为注销事件
|
||||
* MediaSource registration or deregistration event
|
||||
* @param user_data User data pointer set when setting the callback
|
||||
* @param sender Generated MediaSource object
|
||||
* @param regist 1 for registration event, 0 for deregistration event
|
||||
|
||||
* [AUTO-TRANSLATED:4585bbef]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_media_source_regist)(void *user_data, mk_media_source sender, int regist);
|
||||
|
||||
@ -254,12 +426,21 @@ typedef void(API_CALL *on_mk_media_source_regist)(void *user_data, mk_media_sour
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Set MediaSource registration or deregistration event callback function
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:1c3b45be]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_set_on_regist(mk_media ctx, on_mk_media_source_regist cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_set_on_regist2(mk_media ctx, on_mk_media_source_regist cb, void *user_data, on_user_data_free user_data_free);
|
||||
|
||||
/**
|
||||
* rtp推流成功与否的回调(第一次成功后,后面将一直重试)
|
||||
* Callback for whether rtp streaming is successful or not (after the first success, it will retry continuously)
|
||||
|
||||
* [AUTO-TRANSLATED:7e00f7fb]
|
||||
*/
|
||||
typedef on_mk_media_source_send_rtp_result on_mk_media_send_rtp_result;
|
||||
|
||||
@ -273,6 +454,17 @@ typedef on_mk_media_source_send_rtp_result on_mk_media_send_rtp_result;
|
||||
* @param options 选项
|
||||
* @param cb 启动成功或失败回调
|
||||
* @param user_data 回调用户指针
|
||||
* Start sending a ps-rtp stream (distinguished by ssrc), this api is thread-safe
|
||||
* @param ctx Object pointer
|
||||
* @param dst_url Target ip or domain name
|
||||
* @param dst_port Target port
|
||||
* @param ssrc rtp's ssrc, 10-base string print
|
||||
* @param con_type 0: tcp active, 1: udp active, 2: tcp passive, 3: udp passive
|
||||
* @param options Options
|
||||
* @param cb Start success or failure callback
|
||||
* @param user_data Callback user pointer
|
||||
|
||||
* [AUTO-TRANSLATED:dbf694a0]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_start_send_rtp(mk_media ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, on_mk_media_send_rtp_result cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_media_start_send_rtp2(mk_media ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, on_mk_media_send_rtp_result cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -282,12 +474,23 @@ API_EXPORT void API_CALL mk_media_start_send_rtp4(mk_media ctx, const char *dst_
|
||||
* 停止某路或全部ps-rtp发送,此api线程安全
|
||||
* @param ctx 对象指针
|
||||
* @param ssrc rtp的ssrc,10进制的字符串打印,如果为null或空字符串,则停止所有rtp推流
|
||||
* Stop a certain route or all ps-rtp sending, this api is thread-safe
|
||||
* @param ctx Object pointer
|
||||
* @param ssrc rtp's ssrc, 10-base string print, if it is null or empty string, stop all rtp streaming
|
||||
|
||||
* [AUTO-TRANSLATED:6fb2b1df]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_stop_send_rtp(mk_media ctx, const char *ssrc);
|
||||
|
||||
/**
|
||||
* 获取所属线程
|
||||
* @param ctx 对象指针
|
||||
* Get the belonging thread
|
||||
* @param ctx Object pointer
|
||||
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:85a157e8]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_media_get_owner_thread(mk_media ctx);
|
||||
|
||||
|
@ -28,6 +28,14 @@ typedef struct mk_player_t *mk_player;
|
||||
* @param err_msg 错误提示
|
||||
* @param tracks track列表
|
||||
* @param track_count track个数
|
||||
* Callback for playback result or playback interruption event
|
||||
* @param user_data User data pointer
|
||||
* @param err_code Error code, 0 for success
|
||||
* @param err_msg Error message
|
||||
* @param tracks Track list
|
||||
* @param track_count Number of tracks
|
||||
|
||||
* [AUTO-TRANSLATED:38d4c546]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_play_event)(void *user_data, int err_code, const char *err_msg, mk_track tracks[],
|
||||
int track_count);
|
||||
@ -35,12 +43,20 @@ typedef void(API_CALL *on_mk_play_event)(void *user_data, int err_code, const ch
|
||||
/**
|
||||
* 创建一个播放器,支持rtmp[s]/rtsp[s]
|
||||
* @return 播放器指针
|
||||
* Create a player that supports rtmp[s]/rtsp[s]
|
||||
* @return Player pointer
|
||||
|
||||
* [AUTO-TRANSLATED:509f9a50]
|
||||
*/
|
||||
API_EXPORT mk_player API_CALL mk_player_create();
|
||||
|
||||
/**
|
||||
* 销毁播放器
|
||||
* @param ctx 播放器指针
|
||||
* Destroy the player
|
||||
* @param ctx Player pointer
|
||||
|
||||
* [AUTO-TRANSLATED:2448eb93]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_release(mk_player ctx);
|
||||
|
||||
@ -49,6 +65,12 @@ API_EXPORT void API_CALL mk_player_release(mk_player ctx);
|
||||
* @param ctx 播放器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/wait_track_ready
|
||||
* @param val 配置项值,如果是整形,需要转换成统一转换成string
|
||||
* Set player configuration options
|
||||
* @param ctx Player pointer
|
||||
* @param key Configuration key, supports net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/wait_track_ready
|
||||
* @param val Configuration value, if it is an integer, it needs to be converted to a string
|
||||
|
||||
* [AUTO-TRANSLATED:12650e9f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_option(mk_player ctx, const char *key, const char *val);
|
||||
|
||||
@ -56,6 +78,11 @@ API_EXPORT void API_CALL mk_player_set_option(mk_player ctx, const char *key, co
|
||||
* 开始播放url
|
||||
* @param ctx 播放器指针
|
||||
* @param url rtsp[s]/rtmp[s] url
|
||||
* Start playing the url
|
||||
* @param ctx Player pointer
|
||||
* @param url rtsp[s]/rtmp[s] url
|
||||
|
||||
* [AUTO-TRANSLATED:dbec813f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url);
|
||||
|
||||
@ -63,6 +90,11 @@ API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url);
|
||||
* 暂停或恢复播放,仅对点播有用
|
||||
* @param ctx 播放器指针
|
||||
* @param pause 1:暂停播放,0:恢复播放
|
||||
* Pause or resume playback, only useful for on-demand
|
||||
* @param ctx Player pointer
|
||||
* @param pause 1: Pause playback, 0: Resume playback
|
||||
|
||||
* [AUTO-TRANSLATED:28eee990]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause);
|
||||
|
||||
@ -70,6 +102,11 @@ API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause);
|
||||
* 倍数播放,仅对点播有用
|
||||
* @param ctx 播放器指针
|
||||
* @param speed 0.5 1.0 2.0
|
||||
* Playback at a multiple, only useful for on-demand
|
||||
* @param ctx Player pointer
|
||||
* @param speed 0.5 1.0 2.0
|
||||
|
||||
* [AUTO-TRANSLATED:95249ade]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed);
|
||||
|
||||
@ -77,6 +114,11 @@ API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed);
|
||||
* 设置点播进度条
|
||||
* @param ctx 对象指针
|
||||
* @param progress 取值范围未 0.0~1.0
|
||||
* Set the on-demand progress bar
|
||||
* @param ctx Object pointer
|
||||
* @param progress Value range is 0.0~1.0
|
||||
|
||||
* [AUTO-TRANSLATED:cede3a8f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress);
|
||||
|
||||
@ -84,6 +126,11 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress);
|
||||
* 设置点播进度条
|
||||
* @param ctx 对象指针
|
||||
* @param seek_pos 取值范围 相对于开始时间增量 单位秒
|
||||
* Set the on-demand progress bar
|
||||
* @param ctx Object pointer
|
||||
* @param seek_pos Value range is the increment relative to the start time, unit is seconds
|
||||
|
||||
* [AUTO-TRANSLATED:cddea627]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_seekto_pos(mk_player ctx, int seek_pos);
|
||||
|
||||
@ -92,6 +139,12 @@ API_EXPORT void API_CALL mk_player_seekto_pos(mk_player ctx, int seek_pos);
|
||||
* @param ctx 播放器指针
|
||||
* @param cb 回调函数指针,设置null立即取消回调
|
||||
* @param user_data 用户数据指针
|
||||
* Set the player to enable playback result callback function
|
||||
* @param ctx Player pointer
|
||||
* @param cb Callback function pointer, set null to immediately cancel the callback
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:1c2daeaf]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_on_result(mk_player ctx, on_mk_play_event cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_player_set_on_result2(mk_player ctx, on_mk_play_event cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -101,24 +154,43 @@ API_EXPORT void API_CALL mk_player_set_on_result2(mk_player ctx, on_mk_play_even
|
||||
* @param ctx 播放器指针
|
||||
* @param cb 回调函数指针,设置null立即取消回调
|
||||
* @param user_data 用户数据指针
|
||||
* Set the callback for playback being abnormally interrupted
|
||||
* @param ctx Player pointer
|
||||
* @param cb Callback function pointer, set null to immediately cancel the callback
|
||||
* @param user_data User data pointer
|
||||
|
||||
///////////////////////////Audio and video related information interfaces are only valid after the playback success callback is triggered///////////////////////////////
|
||||
* [AUTO-TRANSLATED:18f58697]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_event cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_player_set_on_shutdown2(mk_player ctx, on_mk_play_event cb, void *user_data, on_user_data_free user_data_free);
|
||||
|
||||
///////////////////////////获取音视频相关信息接口在播放成功回调触发后才有效///////////////////////////////
|
||||
// /////////////////////////获取音视频相关信息接口在播放成功回调触发后才有效/////////////////////////////// [AUTO-TRANSLATED:4b53d8ff]
|
||||
// * Get the duration of the on-demand program, if it is live, return 0, otherwise return the number of seconds
|
||||
|
||||
/**
|
||||
* 获取点播节目时长,如果是直播返回0,否则返回秒数
|
||||
* Get the on-demand playback progress, value range is 0.0~1.0
|
||||
|
||||
* [AUTO-TRANSLATED:522140b7]
|
||||
*/
|
||||
API_EXPORT float API_CALL mk_player_duration(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取点播播放进度,取值范围 0.0~1.0
|
||||
* Get the on-demand playback progress position, value range is the increment relative to the start time, unit is seconds
|
||||
|
||||
* [AUTO-TRANSLATED:921795a0]
|
||||
*/
|
||||
API_EXPORT float API_CALL mk_player_progress(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取点播播放进度位置,取值范围 相对于开始时间增量 单位秒
|
||||
* Get the packet loss rate, valid for rtsp
|
||||
* @param ctx Object pointer
|
||||
* @param track_type 0: Video, 1: Audio
|
||||
|
||||
* [AUTO-TRANSLATED:058e5089]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_progress_pos(mk_player ctx);
|
||||
|
||||
|
@ -29,6 +29,16 @@ typedef struct mk_proxy_player_t *mk_proxy_player;
|
||||
* @param hls_enabled 是否生成hls
|
||||
* @param mp4_enabled 是否生成mp4
|
||||
* @return 对象指针
|
||||
* Create a proxy player
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name
|
||||
* @param stream Stream name
|
||||
* @param rtp_type rtsp playback method: RTP_TCP = 0, RTP_UDP = 1, RTP_MULTICAST = 2
|
||||
* @param hls_enabled Whether to generate hls
|
||||
* @param mp4_enabled Whether to generate mp4
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:1d4f13f4]
|
||||
*/
|
||||
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled);
|
||||
|
||||
@ -40,6 +50,14 @@ API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create(const char *vhost, co
|
||||
* @param stream 流名
|
||||
* @param option ProtocolOption相关配置
|
||||
* @return 对象指针
|
||||
* Create a proxy player
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name
|
||||
* @param stream Stream name
|
||||
* @param option ProtocolOption related configuration
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:4c6208df]
|
||||
*/
|
||||
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create2(const char *vhost, const char *app, const char *stream, mk_ini option);
|
||||
|
||||
@ -54,6 +72,17 @@ API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create2(const char *vhost, c
|
||||
* @param mp4_enabled 是否生成mp4
|
||||
* @param retry_count 重试次数,当<0无限次重试
|
||||
* @return 对象指针
|
||||
* Create a proxy player
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name
|
||||
* @param stream Stream name
|
||||
* @param rtp_type rtsp playback method: RTP_TCP = 0, RTP_UDP = 1, RTP_MULTICAST = 2
|
||||
* @param hls_enabled Whether to generate hls
|
||||
* @param mp4_enabled Whether to generate mp4
|
||||
* @param retry_count Retry count, when <0 retry infinitely
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:e25286c3]
|
||||
*/
|
||||
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create3(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled, int retry_count);
|
||||
|
||||
@ -66,6 +95,15 @@ API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create3(const char *vhost, c
|
||||
* @param option ProtocolOption相关配置
|
||||
* @param retry_count 重试次数,当<0无限次重试
|
||||
* @return 对象指针
|
||||
* Create a proxy player
|
||||
* @param vhost Virtual host name, generally __defaultVhost__
|
||||
* @param app Application name
|
||||
* @param stream Stream name
|
||||
* @param option ProtocolOption related configuration
|
||||
* @param retry_count Retry count, when <0 retry infinitely
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:2cb296d1]
|
||||
*/
|
||||
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create4(const char *vhost, const char *app, const char *stream, mk_ini option, int retry_count);
|
||||
|
||||
@ -73,6 +111,10 @@ API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create4(const char *vhost, c
|
||||
/**
|
||||
* 销毁代理播放器
|
||||
* @param ctx 对象指针
|
||||
* Destroy the proxy player
|
||||
* @param ctx Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:fe451691]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_release(mk_proxy_player ctx);
|
||||
|
||||
@ -81,6 +123,12 @@ API_EXPORT void API_CALL mk_proxy_player_release(mk_proxy_player ctx);
|
||||
* @param ctx 代理播放器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/rtsp_speed
|
||||
* @param val 配置项值,如果是整形,需要转换成统一转换成string
|
||||
* Set proxy player configuration options
|
||||
* @param ctx Proxy player pointer
|
||||
* @param key Configuration item key, supports net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/rtsp_speed
|
||||
* @param val Configuration item value, if it is an integer, it needs to be converted to a unified string
|
||||
|
||||
* [AUTO-TRANSLATED:78938fba]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_set_option(mk_proxy_player ctx, const char *key, const char *val);
|
||||
|
||||
@ -88,6 +136,11 @@ API_EXPORT void API_CALL mk_proxy_player_set_option(mk_proxy_player ctx, const c
|
||||
* 开始播放
|
||||
* @param ctx 对象指针
|
||||
* @param url 播放url,支持rtsp/rtmp
|
||||
* Start playback
|
||||
* @param ctx Object pointer
|
||||
* @param url Playback url, supports rtsp/rtmp
|
||||
|
||||
* [AUTO-TRANSLATED:9597bafb]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_play(mk_proxy_player ctx, const char *url);
|
||||
|
||||
@ -97,9 +150,17 @@ API_EXPORT void API_CALL mk_proxy_player_play(mk_proxy_player ctx, const char *u
|
||||
* 你应该通过该事件调用mk_proxy_player_release函数并且释放其他资源
|
||||
* 如果你不调用mk_proxy_player_release函数,那么MediaSource.close()操作将无效
|
||||
* @param user_data 用户数据指针,通过mk_proxy_player_set_on_close函数设置
|
||||
* MediaSource.close() callback event
|
||||
* When you choose to close an associated MediaSource, it will eventually trigger this callback
|
||||
* You should call mk_proxy_player_release function through this event and release other resources
|
||||
* If you do not call mk_proxy_player_release function, then MediaSource.close() operation will be invalid
|
||||
* @param user_data User data pointer, set by mk_proxy_player_set_on_close function
|
||||
|
||||
* [AUTO-TRANSLATED:c99b6bfd]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_proxy_player_cb)(void *user_data, int err, const char *what, int sys_err);
|
||||
// 保持兼容
|
||||
// 保持兼容 [AUTO-TRANSLATED:94139ca7]
|
||||
// Keep compatible
|
||||
#define on_mk_proxy_player_close on_mk_proxy_player_cb
|
||||
|
||||
/**
|
||||
@ -109,6 +170,14 @@ typedef void(API_CALL *on_mk_proxy_player_cb)(void *user_data, int err, const ch
|
||||
* @param ctx 对象指针
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* Listen for MediaSource.close() event
|
||||
* When you choose to close an associated MediaSource, it will eventually trigger this callback
|
||||
* You should call mk_proxy_player_release function through this event and release other resources
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:174060d4]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_set_on_close(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -119,6 +188,13 @@ API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_m
|
||||
* @param cb 回调指针
|
||||
* @param user_data 用户数据指针
|
||||
* @param user_data_free 用户数据释放回调
|
||||
* Set the proxy's first playback result callback. If the first playback fails, it can be considered a startup failure.
|
||||
* @param ctx Object pointer
|
||||
* @param cb Callback pointer
|
||||
* @param user_data User data pointer
|
||||
* @param user_data_free User data release callback
|
||||
|
||||
* [AUTO-TRANSLATED:1f34852a]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_set_on_play_result(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data, on_user_data_free user_data_free);
|
||||
|
||||
@ -126,6 +202,11 @@ API_EXPORT void API_CALL mk_proxy_player_set_on_play_result(mk_proxy_player ctx,
|
||||
* 获取总的观看人数
|
||||
* @param ctx 对象指针
|
||||
* @return 观看人数
|
||||
* Get the total number of viewers
|
||||
* @param ctx Object pointer
|
||||
* @return Number of viewers
|
||||
|
||||
* [AUTO-TRANSLATED:56635caf]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_proxy_player_total_reader_count(mk_proxy_player ctx);
|
||||
|
||||
|
@ -25,6 +25,12 @@ typedef struct mk_pusher_t *mk_pusher;
|
||||
* @param user_data 用户数据指针
|
||||
* @param err_code 错误代码,0为成功
|
||||
* @param err_msg 错误提示
|
||||
* Callback for streaming result or streaming interruption event
|
||||
* @param user_data User data pointer
|
||||
* @param err_code Error code, 0 for success
|
||||
* @param err_msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:6e7d5c79]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_push_event)(void *user_data,int err_code,const char *err_msg);
|
||||
|
||||
@ -38,6 +44,17 @@ typedef void(API_CALL *on_mk_push_event)(void *user_data,int err_code,const char
|
||||
* @param app 绑定的MediaSource对象的应用名,一般为live
|
||||
* @param stream 绑定的MediaSource对象的流id
|
||||
* @return 对象指针
|
||||
* Bind the MediaSource object and create an rtmp[s]/rtsp[s] pusher
|
||||
* MediaSource is generated by mk_media_create or mk_proxy_player_create or streaming
|
||||
* The MediaSource object must be registered
|
||||
*
|
||||
* @param schema Protocol to which the bound MediaSource object belongs, supporting rtsp/rtmp
|
||||
* @param vhost Virtual host of the bound MediaSource object, generally __defaultVhost__
|
||||
* @param app Application name of the bound MediaSource object, generally live
|
||||
* @param stream Stream id of the bound MediaSource object
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:9366fdbc]
|
||||
*/
|
||||
API_EXPORT mk_pusher API_CALL mk_pusher_create(const char *schema,const char *vhost,const char *app, const char *stream);
|
||||
|
||||
@ -48,12 +65,24 @@ API_EXPORT mk_pusher API_CALL mk_pusher_create(const char *schema,const char *vh
|
||||
*
|
||||
* @param src MediaSource对象
|
||||
* @return 对象指针
|
||||
* Bind the MediaSource object and create an rtmp[s]/rtsp[s] pusher
|
||||
* MediaSource is generated by mk_media_create or mk_proxy_player_create or streaming
|
||||
* The MediaSource object must be registered
|
||||
*
|
||||
* @param src MediaSource object
|
||||
* @return Object pointer
|
||||
|
||||
* [AUTO-TRANSLATED:34ca024a]
|
||||
*/
|
||||
API_EXPORT mk_pusher API_CALL mk_pusher_create_src(mk_media_source src);
|
||||
|
||||
/**
|
||||
* 释放推流器
|
||||
* @param ctx 推流器指针
|
||||
* Release the pusher
|
||||
* @param ctx Pusher pointer
|
||||
|
||||
* [AUTO-TRANSLATED:55fd6b8b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_release(mk_pusher ctx);
|
||||
|
||||
@ -62,6 +91,12 @@ API_EXPORT void API_CALL mk_pusher_release(mk_pusher ctx);
|
||||
* @param ctx 推流器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
|
||||
* @param val 配置项值,如果是整形,需要转换成统一转换成string
|
||||
* Set the pusher configuration options
|
||||
* @param ctx Pusher pointer
|
||||
* @param key Configuration item key, supports net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
|
||||
* @param val Configuration item value, if it is an integer, it needs to be converted to a unified string
|
||||
|
||||
* [AUTO-TRANSLATED:0e3ce06d]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_set_option(mk_pusher ctx, const char *key, const char *val);
|
||||
|
||||
@ -69,6 +104,11 @@ API_EXPORT void API_CALL mk_pusher_set_option(mk_pusher ctx, const char *key, co
|
||||
* 开始推流
|
||||
* @param ctx 推流器指针
|
||||
* @param url 推流地址,支持rtsp[s]/rtmp[s]
|
||||
* Start streaming
|
||||
* @param ctx Pusher pointer
|
||||
* @param url Streaming address, supports rtsp[s]/rtmp[s]
|
||||
|
||||
* [AUTO-TRANSLATED:45c0a836]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_publish(mk_pusher ctx,const char *url);
|
||||
|
||||
@ -77,6 +117,12 @@ API_EXPORT void API_CALL mk_pusher_publish(mk_pusher ctx,const char *url);
|
||||
* @param ctx 推流器指针
|
||||
* @param cb 回调函数指针,不得为null
|
||||
* @param user_data 用户数据指针
|
||||
* Set the pusher streaming result callback function
|
||||
* @param ctx Pusher pointer
|
||||
* @param cb Callback function pointer, must not be null
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:a45fb6e4]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_set_on_result(mk_pusher ctx, on_mk_push_event cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_pusher_set_on_result2(mk_pusher ctx, on_mk_push_event cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -86,6 +132,12 @@ API_EXPORT void API_CALL mk_pusher_set_on_result2(mk_pusher ctx, on_mk_push_even
|
||||
* @param ctx 推流器指针
|
||||
* @param cb 回调函数指针,不得为null
|
||||
* @param user_data 用户数据指针
|
||||
* Set the callback for the streaming being abnormally interrupted
|
||||
* @param ctx Pusher pointer
|
||||
* @param cb Callback function pointer, must not be null
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:9e11a215]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_set_on_shutdown(mk_pusher ctx, on_mk_push_event cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_pusher_set_on_shutdown2(mk_pusher ctx, on_mk_push_event cb, void *user_data, on_user_data_free user_data_free);
|
||||
|
@ -17,6 +17,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// /////////////////////////////////////////flv录制///////////////////////////////////////////// [AUTO-TRANSLATED:a084663f]
|
||||
// /////////////////////////////////////////flv录制/////////////////////////////////////////////
|
||||
|
||||
typedef struct mk_flv_recorder_t *mk_flv_recorder;
|
||||
@ -24,12 +25,20 @@ typedef struct mk_flv_recorder_t *mk_flv_recorder;
|
||||
/**
|
||||
* 创建flv录制器
|
||||
* @return
|
||||
* Create flv recorder
|
||||
* @return
|
||||
|
||||
* [AUTO-TRANSLATED:7582cde1]
|
||||
*/
|
||||
API_EXPORT mk_flv_recorder API_CALL mk_flv_recorder_create();
|
||||
|
||||
/**
|
||||
* 释放flv录制器
|
||||
* @param ctx
|
||||
* Release flv recorder
|
||||
* @param ctx
|
||||
|
||||
* [AUTO-TRANSLATED:c33c76bb]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_flv_recorder_release(mk_flv_recorder ctx);
|
||||
|
||||
@ -41,9 +50,19 @@ API_EXPORT void API_CALL mk_flv_recorder_release(mk_flv_recorder ctx);
|
||||
* @param stream 绑定的RtmpMediaSource的 stream名
|
||||
* @param file_path 文件存放地址
|
||||
* @return 0:开始超过,-1:失败,打开文件失败或该RtmpMediaSource不存在
|
||||
* Start recording flv
|
||||
* @param ctx flv recorder
|
||||
* @param vhost virtual host
|
||||
* @param app app name of the bound RtmpMediaSource
|
||||
* @param stream stream name of the bound RtmpMediaSource
|
||||
* @param file_path file storage address
|
||||
* @return 0: start exceeds, -1: failure, file opening fails or the RtmpMediaSource does not exist
|
||||
|
||||
* [AUTO-TRANSLATED:194cf3de]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *vhost, const char *app, const char *stream, const char *file_path);
|
||||
|
||||
// /////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// [AUTO-TRANSLATED:99c61c68]
|
||||
// /////////////////////////////////////////hls/mp4录制/////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
@ -53,6 +72,14 @@ API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *v
|
||||
* @param app 应用名
|
||||
* @param stream 流id
|
||||
* @return 录制状态,0:未录制, 1:正在录制
|
||||
* Get recording status
|
||||
* @param type 0: hls, 1: MP4
|
||||
* @param vhost virtual host
|
||||
* @param app application name
|
||||
* @param stream stream id
|
||||
* @return recording status, 0: not recording, 1: recording
|
||||
|
||||
* [AUTO-TRANSLATED:0b1d374a]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_recorder_is_recording(int type, const char *vhost, const char *app, const char *stream);
|
||||
|
||||
@ -65,6 +92,16 @@ API_EXPORT int API_CALL mk_recorder_is_recording(int type, const char *vhost, co
|
||||
* @param customized_path 录像文件保存自定义目录,默认为空或null则自动生成
|
||||
* @param max_second mp4录制最大切片时间,单位秒,置0则采用配置文件配置
|
||||
* @return 1代表成功,0代表失败
|
||||
* Start recording
|
||||
* @param type 0: hls-ts, 1: MP4, 2: hls-fmp4, 3: http-fmp4, 4: http-ts
|
||||
* @param vhost virtual host
|
||||
* @param app application name
|
||||
* @param stream stream id
|
||||
* @param customized_path custom directory for saving recording files, defaults to empty or null, automatically generated
|
||||
* @param max_second maximum slice time for mp4 recording, in seconds, set to 0 to use the configuration file configuration
|
||||
* @return 1 represents success, 0 represents failure
|
||||
|
||||
* [AUTO-TRANSLATED:0a1c8c3e]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const char *app, const char *stream, const char *customized_path, size_t max_second);
|
||||
|
||||
@ -75,6 +112,15 @@ API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const cha
|
||||
* @param app 应用名
|
||||
* @param stream 流id
|
||||
* @return 1:成功,0:失败
|
||||
* Stop recording
|
||||
* @param type 0: hls-ts, 1: MP4, 2: hls-fmp4, 3: http-fmp4, 4: http-ts
|
||||
* @param vhost virtual host
|
||||
* @param app application name
|
||||
* @param stream stream id
|
||||
* @return 1: success, 0: failure
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:df1638e7]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_recorder_stop(int type, const char *vhost, const char *app, const char *stream);
|
||||
|
||||
|
@ -22,12 +22,22 @@ typedef struct mk_rtp_server_t *mk_rtp_server;
|
||||
* @param tcp_mode tcp模式(0: 不监听端口 1: 监听端口 2: 主动连接到服务端)
|
||||
* @param stream_id 该端口绑定的流id
|
||||
* @return
|
||||
* Create GB28181 RTP server
|
||||
* @param port Listening port, 0 for random
|
||||
* @param tcp_mode tcp mode (0: not listening to port 1: listening to port 2: actively connect to the server)
|
||||
* @param stream_id Stream id bound to this port
|
||||
* @return
|
||||
|
||||
* [AUTO-TRANSLATED:0c5fd548]
|
||||
*/
|
||||
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create(uint16_t port, int tcp_mode, const char *stream_id);
|
||||
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create2(uint16_t port, int tcp_mode, const char *vhost, const char *app, const char *stream_id);
|
||||
|
||||
/**
|
||||
* TCP 主动模式时连接到服务器是否成功的回调
|
||||
* Callback for whether the connection to the server is successful in TCP active mode
|
||||
|
||||
* [AUTO-TRANSLATED:752e915a]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_rtp_server_connected)(void *user_data, int err, const char *what, int sys_err);
|
||||
|
||||
@ -39,6 +49,15 @@ typedef void(API_CALL *on_mk_rtp_server_connected)(void *user_data, int err, con
|
||||
* @param cb 连接到服务器是否成功的回调
|
||||
* @param user_data 用户数据指针
|
||||
* @return
|
||||
* Connect to the server in TCP active mode
|
||||
* @param @param ctx Server object
|
||||
* @param dst_url Server address
|
||||
* @param dst_port Server port
|
||||
* @param cb Callback for whether the connection to the server is successful
|
||||
* @param user_data User data pointer
|
||||
* @return
|
||||
|
||||
* [AUTO-TRANSLATED:e827d45a]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtp_server_connect(mk_rtp_server ctx, const char *dst_url, uint16_t dst_port, on_mk_rtp_server_connected cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_rtp_server_connect2(mk_rtp_server ctx, const char *dst_url, uint16_t dst_port, on_mk_rtp_server_connected cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -46,6 +65,10 @@ API_EXPORT void API_CALL mk_rtp_server_connect2(mk_rtp_server ctx, const char *d
|
||||
/**
|
||||
* 销毁GB28181 RTP 服务器
|
||||
* @param ctx 服务器对象
|
||||
* Destroy GB28181 RTP server
|
||||
* @param ctx Server object
|
||||
|
||||
* [AUTO-TRANSLATED:828e02f0]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtp_server_release(mk_rtp_server ctx);
|
||||
|
||||
@ -53,12 +76,21 @@ API_EXPORT void API_CALL mk_rtp_server_release(mk_rtp_server ctx);
|
||||
* 获取本地监听的端口号
|
||||
* @param ctx 服务器对象
|
||||
* @return 端口号
|
||||
* Get the local listening port number
|
||||
* @param ctx Server object
|
||||
* @return Port number
|
||||
|
||||
* [AUTO-TRANSLATED:90fe5d22]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_rtp_server_port(mk_rtp_server ctx);
|
||||
|
||||
/**
|
||||
* GB28181 RTP 服务器接收流超时时触发
|
||||
* @param user_data 用户数据指针
|
||||
* Triggered when the GB28181 RTP server receives a stream timeout
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:04d56f24]
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_rtp_server_detach)(void *user_data);
|
||||
|
||||
@ -67,6 +99,13 @@ typedef void(API_CALL *on_mk_rtp_server_detach)(void *user_data);
|
||||
* @param ctx 服务器对象
|
||||
* @param cb 回调函数
|
||||
* @param user_data 回调函数用户数据指针
|
||||
* Listen for B28181 RTP server receiving stream timeout events
|
||||
* @param ctx Server object
|
||||
* @param cb Callback function
|
||||
* @param user_data Callback function user data pointer
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:a88c239f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_rtp_server_set_on_detach(mk_rtp_server ctx, on_mk_rtp_server_detach cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_rtp_server_set_on_detach2(mk_rtp_server ctx, on_mk_rtp_server_detach cb, void *user_data, on_user_data_free user_data_free);
|
||||
|
@ -29,6 +29,14 @@ typedef void(API_CALL *on_mk_buffer_free)(void *user_data, void *data);
|
||||
* @param cb 数据指针free回调函数,该参数置空时,内部会拷贝数据
|
||||
* @param user_data 数据指针free回调函数on_mk_buffer_free第一个参数
|
||||
* @return buffer对象
|
||||
* Create a buffer object
|
||||
* @param data Data pointer
|
||||
* @param len Data length
|
||||
* @param cb Data pointer free callback function. This parameter is set to null, the data will be copied internally
|
||||
* @param user_data The first parameter of the data pointer free callback function on_mk_buffer_free
|
||||
* @return buffer object
|
||||
|
||||
* [AUTO-TRANSLATED:933f9ad8]
|
||||
*/
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_from_char(const char *data, size_t len, on_mk_buffer_free cb, void *user_data);
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_from_char2(const char *data, size_t len, on_mk_buffer_free cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -38,7 +46,8 @@ API_EXPORT const char* API_CALL mk_buffer_get_data(mk_buffer buffer);
|
||||
API_EXPORT size_t API_CALL mk_buffer_get_size(mk_buffer buffer);
|
||||
|
||||
///////////////////////////////////////////SockInfo/////////////////////////////////////////////
|
||||
//SockInfo对象的C映射
|
||||
// SockInfo对象的C映射 [AUTO-TRANSLATED:6bc64f0f]
|
||||
// C mapping of SockInfo object
|
||||
typedef struct mk_sock_info_t *mk_sock_info;
|
||||
|
||||
//SockInfo::get_peer_ip()
|
||||
@ -52,24 +61,28 @@ API_EXPORT uint16_t API_CALL mk_sock_info_local_port(const mk_sock_info ctx);
|
||||
|
||||
#ifndef SOCK_INFO_API_RENAME
|
||||
#define SOCK_INFO_API_RENAME
|
||||
//mk_tcp_session对象转换成mk_sock_info对象后再获取网络相关信息
|
||||
// mk_tcp_session对象转换成mk_sock_info对象后再获取网络相关信息 [AUTO-TRANSLATED:bd727f26]
|
||||
// Get network information after converting mk_tcp_session object to mk_sock_info object
|
||||
#define mk_tcp_session_peer_ip(x,buf) mk_sock_info_peer_ip(mk_tcp_session_get_sock_info(x),buf)
|
||||
#define mk_tcp_session_local_ip(x,buf) mk_sock_info_local_ip(mk_tcp_session_get_sock_info(x),buf)
|
||||
#define mk_tcp_session_peer_port(x) mk_sock_info_peer_port(mk_tcp_session_get_sock_info(x))
|
||||
#define mk_tcp_session_local_port(x) mk_sock_info_local_port(mk_tcp_session_get_sock_info(x))
|
||||
|
||||
//mk_tcp_client对象转换成mk_sock_info对象后再获取网络相关信息
|
||||
// mk_tcp_client对象转换成mk_sock_info对象后再获取网络相关信息 [AUTO-TRANSLATED:e642eaac]
|
||||
// Get network information after converting mk_tcp_client object to mk_sock_info object
|
||||
#define mk_tcp_client_peer_ip(x,buf) mk_sock_info_peer_ip(mk_tcp_client_get_sock_info(x),buf)
|
||||
#define mk_tcp_client_local_ip(x,buf) mk_sock_info_local_ip(mk_tcp_client_get_sock_info(x),buf)
|
||||
#define mk_tcp_client_peer_port(x) mk_sock_info_peer_port(mk_tcp_client_get_sock_info(x))
|
||||
#define mk_tcp_client_local_port(x) mk_sock_info_local_port(mk_tcp_client_get_sock_info(x))
|
||||
#endif
|
||||
///////////////////////////////////////////TcpSession/////////////////////////////////////////////
|
||||
//TcpSession对象的C映射
|
||||
// TcpSession对象的C映射 [AUTO-TRANSLATED:df12e714]
|
||||
// C mapping of TcpSession object
|
||||
typedef struct mk_tcp_session_t *mk_tcp_session;
|
||||
typedef struct mk_tcp_session_ref_t *mk_tcp_session_ref;
|
||||
|
||||
//获取基类指针以便获取其网络相关信息
|
||||
// 获取基类指针以便获取其网络相关信息 [AUTO-TRANSLATED:725bdbd0]
|
||||
// Get the base class pointer to get its network information
|
||||
API_EXPORT mk_sock_info API_CALL mk_tcp_session_get_sock_info(const mk_tcp_session ctx);
|
||||
|
||||
//TcpSession::safeShutdown()
|
||||
@ -78,24 +91,34 @@ API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int er
|
||||
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx, const char *data, size_t len);
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer(const mk_tcp_session ctx, mk_buffer buffer);
|
||||
|
||||
//切换到该对象所在线程后再TcpSession::send()
|
||||
// 切换到该对象所在线程后再TcpSession::send() [AUTO-TRANSLATED:8a8f72ac]
|
||||
// Switch to the thread where the object is located, then TcpSession::send()
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx, const char *data, size_t len);
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer_safe(const mk_tcp_session ctx, mk_buffer buffer);
|
||||
|
||||
//创建mk_tcp_session的强引用
|
||||
// 创建mk_tcp_session的强引用 [AUTO-TRANSLATED:9dff998d]
|
||||
// Create a strong reference to mk_tcp_session
|
||||
API_EXPORT mk_tcp_session_ref API_CALL mk_tcp_session_ref_from(const mk_tcp_session ctx);
|
||||
//删除mk_tcp_session的强引用
|
||||
// 删除mk_tcp_session的强引用 [AUTO-TRANSLATED:583848b0]
|
||||
// Delete the strong reference to mk_tcp_session
|
||||
API_EXPORT void mk_tcp_session_ref_release(const mk_tcp_session_ref ref);
|
||||
//根据强引用获取mk_tcp_session
|
||||
// 根据强引用获取mk_tcp_session [AUTO-TRANSLATED:4bf1f7a0]
|
||||
// Get mk_tcp_session according to the strong reference
|
||||
API_EXPORT mk_tcp_session mk_tcp_session_from_ref(const mk_tcp_session_ref ref);
|
||||
|
||||
///////////////////////////////////////////自定义tcp服务/////////////////////////////////////////////
|
||||
// /////////////////////////////////////////自定义tcp服务///////////////////////////////////////////// [AUTO-TRANSLATED:25f12aa6]
|
||||
// /////////////////////////////////////////Custom tcp service/////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* 收到mk_tcp_session创建对象
|
||||
* @param server_port 服务器端口号
|
||||
* @param session 会话处理对象
|
||||
* Receive mk_tcp_session create object
|
||||
* @param server_port Server port number
|
||||
* @param session Session processing object
|
||||
|
||||
* [AUTO-TRANSLATED:58183e28]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_session_create)(uint16_t server_port,mk_tcp_session session);
|
||||
|
||||
@ -104,6 +127,12 @@ typedef struct {
|
||||
* @param server_port 服务器端口号
|
||||
* @param session 会话处理对象
|
||||
* @param buffer 数据
|
||||
* Receive data sent by the client
|
||||
* @param server_port Server port number
|
||||
* @param session Session processing object
|
||||
* @param buffer Data
|
||||
|
||||
* [AUTO-TRANSLATED:ff2132fa]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_session_data)(uint16_t server_port,mk_tcp_session session, mk_buffer buffer);
|
||||
|
||||
@ -111,6 +140,11 @@ typedef struct {
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
* @param server_port 服务器端口号
|
||||
* @param session 会话处理对象
|
||||
* Timer every 2 seconds, used to manage timeout tasks
|
||||
* @param server_port Server port number
|
||||
* @param session Session processing object
|
||||
|
||||
* [AUTO-TRANSLATED:5d36ea59]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_session_manager)(uint16_t server_port,mk_tcp_session session);
|
||||
|
||||
@ -120,19 +154,30 @@ typedef struct {
|
||||
* @param session 会话处理对象
|
||||
* @param code 错误代码
|
||||
* @param msg 错误提示
|
||||
* Generally triggered by client disconnecting tcp
|
||||
* @param server_port Server port number
|
||||
* @param session Session processing object
|
||||
* @param code Error code
|
||||
* @param msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:a2e6ce8b]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_session_disconnect)(uint16_t server_port,mk_tcp_session session,int code,const char *msg);
|
||||
} mk_tcp_session_events;
|
||||
|
||||
|
||||
typedef enum {
|
||||
//普通的tcp
|
||||
// 普通的tcp [AUTO-TRANSLATED:b4035d33]
|
||||
// Ordinary tcp
|
||||
mk_type_tcp = 0,
|
||||
//ssl类型的tcp
|
||||
// ssl类型的tcp [AUTO-TRANSLATED:88792584]
|
||||
// ssl type tcp
|
||||
mk_type_ssl = 1,
|
||||
//基于websocket的连接
|
||||
// 基于websocket的连接 [AUTO-TRANSLATED:01f3223d]
|
||||
// Websocket based connection
|
||||
mk_type_ws = 2,
|
||||
//基于ssl websocket的连接
|
||||
// 基于ssl websocket的连接 [AUTO-TRANSLATED:86411da9]
|
||||
// Ssl websocket based connection
|
||||
mk_type_wss = 3
|
||||
}mk_tcp_type;
|
||||
|
||||
@ -141,6 +186,12 @@ typedef enum {
|
||||
* 该函数只对mk_tcp_server_server_start启动的服务类型有效
|
||||
* @param session 会话对象
|
||||
* @param user_data 用户数据指针
|
||||
* Attach user data to the tcp session object
|
||||
* This function is only valid for services started by mk_tcp_server_server_start
|
||||
* @param session Session object
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:272bd460]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_session_set_user_data(mk_tcp_session session, void *user_data);
|
||||
API_EXPORT void API_CALL mk_tcp_session_set_user_data2(mk_tcp_session session, void *user_data, on_user_data_free user_data_free);
|
||||
@ -150,6 +201,12 @@ API_EXPORT void API_CALL mk_tcp_session_set_user_data2(mk_tcp_session session, v
|
||||
* 该函数只对mk_tcp_server_server_start启动的服务类型有效
|
||||
* @param session tcp会话对象
|
||||
* @return 用户数据指针
|
||||
* Get the user data attached to the tcp session object
|
||||
* This function is only valid for services started by mk_tcp_server_server_start
|
||||
* @param session Tcp session object
|
||||
* @return User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:8047a5a4]
|
||||
*/
|
||||
API_EXPORT void* API_CALL mk_tcp_session_get_user_data(mk_tcp_session session);
|
||||
|
||||
@ -157,19 +214,29 @@ API_EXPORT void* API_CALL mk_tcp_session_get_user_data(mk_tcp_session session);
|
||||
* 开启tcp服务器
|
||||
* @param port 监听端口号,0则为随机
|
||||
* @param type 服务器类型
|
||||
* Start tcp server
|
||||
* @param port Listening port number, 0 is random
|
||||
* @param type Server type
|
||||
|
||||
* [AUTO-TRANSLATED:ad27f0ed]
|
||||
*/
|
||||
API_EXPORT uint16_t API_CALL mk_tcp_server_start(uint16_t port, mk_tcp_type type);
|
||||
|
||||
/**
|
||||
* 监听tcp服务器事件
|
||||
* Listen for tcp server events
|
||||
|
||||
* [AUTO-TRANSLATED:7ca82a56]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_server_events_listen(const mk_tcp_session_events *events);
|
||||
|
||||
|
||||
///////////////////////////////////////////自定义tcp客户端/////////////////////////////////////////////
|
||||
// /////////////////////////////////////////自定义tcp客户端///////////////////////////////////////////// [AUTO-TRANSLATED:e5ae198e]
|
||||
// /////////////////////////////////////////Custom tcp client/////////////////////////////////////////////
|
||||
|
||||
typedef struct mk_tcp_client_t *mk_tcp_client;
|
||||
//获取基类指针以便获取其网络相关信息
|
||||
// 获取基类指针以便获取其网络相关信息 [AUTO-TRANSLATED:725bdbd0]
|
||||
// Get the base class pointer to get its network information
|
||||
API_EXPORT mk_sock_info API_CALL mk_tcp_client_get_sock_info(const mk_tcp_client ctx);
|
||||
|
||||
typedef struct {
|
||||
@ -178,6 +245,12 @@ typedef struct {
|
||||
* @param client tcp客户端
|
||||
* @param code 0为连接成功,否则为失败原因
|
||||
* @param msg 连接失败错误提示
|
||||
* Tcp client connects to server successfully or fails callback
|
||||
* @param client Tcp client
|
||||
* @param code 0 for successful connection, otherwise for failure reason
|
||||
* @param msg Connection failure error message
|
||||
|
||||
* [AUTO-TRANSLATED:2b38e72a]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_client_connect)(mk_tcp_client client,int code,const char *msg);
|
||||
|
||||
@ -187,6 +260,13 @@ typedef struct {
|
||||
* @param client tcp客户端
|
||||
* @param code 错误代码
|
||||
* @param msg 错误提示
|
||||
* Tcp client disconnects from tcp server callback
|
||||
* Generally caused by eof event
|
||||
* @param client Tcp client
|
||||
* @param code Error code
|
||||
* @param msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:5658c1c5]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_client_disconnect)(mk_tcp_client client,int code,const char *msg);
|
||||
|
||||
@ -194,12 +274,21 @@ typedef struct {
|
||||
* 收到tcp服务器发来的数据
|
||||
* @param client tcp客户端
|
||||
* @param buffer 数据
|
||||
* Receive data sent by the tcp server
|
||||
* @param client Tcp client
|
||||
* @param buffer Data
|
||||
|
||||
* [AUTO-TRANSLATED:4a225334]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_client_data)(mk_tcp_client client, mk_buffer buffer);
|
||||
|
||||
/**
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
* @param client tcp客户端
|
||||
* Timer every 2 seconds, used to manage timeout tasks
|
||||
* @param client Tcp client
|
||||
|
||||
* [AUTO-TRANSLATED:05f637ef]
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_client_manager)(mk_tcp_client client);
|
||||
} mk_tcp_client_events;
|
||||
@ -210,12 +299,23 @@ typedef struct {
|
||||
* @param user_data 用户数据指针
|
||||
* @param type 客户端类型
|
||||
* @return 客户端对象
|
||||
* Create tcp client
|
||||
* @param events Callback function structure
|
||||
* @param user_data User data pointer
|
||||
* @param type Client type
|
||||
* @return Client object
|
||||
|
||||
* [AUTO-TRANSLATED:01191226]
|
||||
*/
|
||||
API_EXPORT mk_tcp_client API_CALL mk_tcp_client_create(mk_tcp_client_events *events, mk_tcp_type type);
|
||||
|
||||
/**
|
||||
* 释放tcp客户端
|
||||
* @param ctx 客户端对象
|
||||
* Release the tcp client
|
||||
* @param ctx Client object
|
||||
|
||||
* [AUTO-TRANSLATED:b3a75d23]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_release(mk_tcp_client ctx);
|
||||
|
||||
@ -225,6 +325,13 @@ API_EXPORT void API_CALL mk_tcp_client_release(mk_tcp_client ctx);
|
||||
* @param host 服务器ip或域名
|
||||
* @param port 服务器端口号
|
||||
* @param time_out_sec 超时时间
|
||||
* Initiate connection
|
||||
* @param ctx Client object
|
||||
* @param host Server ip or domain name
|
||||
* @param port Server port number
|
||||
* @param time_out_sec Timeout time
|
||||
|
||||
* [AUTO-TRANSLATED:dd45e0fa]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *host, uint16_t port, float time_out_sec);
|
||||
|
||||
@ -234,6 +341,13 @@ API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *ho
|
||||
* @param ctx 客户端对象
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度,等于0时,内部通过strlen获取
|
||||
* Non-thread-safe data sending
|
||||
* Developers can call this function if they can ensure that it is within the network thread of this object
|
||||
* @param ctx Client object
|
||||
* @param data Data pointer
|
||||
* @param len Data length, 0 means get it by strlen internally
|
||||
|
||||
* [AUTO-TRANSLATED:a5e2ac86]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len);
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer(mk_tcp_client ctx, mk_buffer buffer);
|
||||
@ -243,6 +357,12 @@ API_EXPORT void API_CALL mk_tcp_client_send_buffer(mk_tcp_client ctx, mk_buffer
|
||||
* @param ctx 客户端对象
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度,等于0时,内部通过strlen获取
|
||||
* Send data after switching to the network thread of this object
|
||||
* @param ctx Client object
|
||||
* @param data Data pointer
|
||||
* @param len Data length, 0 means get it by strlen internally
|
||||
|
||||
* [AUTO-TRANSLATED:95dc75f8]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_safe(mk_tcp_client ctx, const char *data, int len);
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer_safe(mk_tcp_client ctx, mk_buffer buffer);
|
||||
@ -251,6 +371,11 @@ API_EXPORT void API_CALL mk_tcp_client_send_buffer_safe(mk_tcp_client ctx, mk_bu
|
||||
* 客户端附着用户数据
|
||||
* @param ctx 客户端对象
|
||||
* @param user_data 用户数据指针
|
||||
* Client attaches user data
|
||||
* @param ctx Client object
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:a9d4840b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_set_user_data(mk_tcp_client ctx, void *user_data);
|
||||
API_EXPORT void API_CALL mk_tcp_client_set_user_data2(mk_tcp_client ctx, void *user_data, on_user_data_free user_data_free);
|
||||
@ -259,6 +384,12 @@ API_EXPORT void API_CALL mk_tcp_client_set_user_data2(mk_tcp_client ctx, void *u
|
||||
* 获取客户端对象上附着的用户数据
|
||||
* @param ctx 客户端对象
|
||||
* @return 用户数据指针
|
||||
* Get the user data attached to the client object
|
||||
* @param ctx Client object
|
||||
* @return User data pointer
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7f74985b]
|
||||
*/
|
||||
API_EXPORT void* API_CALL mk_tcp_client_get_user_data(mk_tcp_client ctx);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// /////////////////////////////////////////事件线程///////////////////////////////////////////// [AUTO-TRANSLATED:6d564b3b]
|
||||
// /////////////////////////////////////////事件线程/////////////////////////////////////////////
|
||||
typedef struct mk_thread_t *mk_thread;
|
||||
|
||||
@ -26,6 +27,11 @@ typedef struct mk_thread_t *mk_thread;
|
||||
* 获取tcp会话对象所在事件线程
|
||||
* @param ctx tcp会话对象
|
||||
* @return 对象所在事件线程
|
||||
* Get the event thread where the tcp session object is located
|
||||
* @param ctx tcp session object
|
||||
* @return The event thread where the object is located
|
||||
|
||||
* [AUTO-TRANSLATED:17da57ec]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_tcp_session(mk_tcp_session ctx);
|
||||
|
||||
@ -33,6 +39,11 @@ API_EXPORT mk_thread API_CALL mk_thread_from_tcp_session(mk_tcp_session ctx);
|
||||
* 获取tcp客户端对象所在事件线程
|
||||
* @param ctx tcp客户端
|
||||
* @return 对象所在事件线程
|
||||
* Get the event thread where the tcp client object is located
|
||||
* @param ctx tcp client
|
||||
* @return The event thread where the object is located
|
||||
|
||||
* [AUTO-TRANSLATED:15d4174b]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_tcp_client(mk_tcp_client ctx);
|
||||
|
||||
@ -41,6 +52,12 @@ API_EXPORT mk_thread API_CALL mk_thread_from_tcp_client(mk_tcp_client ctx);
|
||||
* 如果在事件线程内执行此函数将返回本事件线程
|
||||
* 事件线程指的是定时器、网络io事件线程
|
||||
* @return 事件线程
|
||||
* Get an event thread randomly from the event thread pool according to the load balancing algorithm
|
||||
* If this function is executed within the event thread, it will return the current event thread
|
||||
* Event thread refers to timer, network io event thread
|
||||
* @return Event thread
|
||||
|
||||
* [AUTO-TRANSLATED:5da37e1f]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_pool();
|
||||
|
||||
@ -49,6 +66,12 @@ API_EXPORT mk_thread API_CALL mk_thread_from_pool();
|
||||
* 后台线程本质与事件线程相同,只是优先级更低,同时可以执行短时间的阻塞任务
|
||||
* ZLMediaKit中后台线程用于dns解析、mp4点播时的文件解复用
|
||||
* @return 后台线程
|
||||
* Get a thread randomly from the background thread pool according to the load balancing algorithm
|
||||
* Background threads are essentially the same as event threads, but they have lower priority and can execute short-term blocking tasks
|
||||
* Background threads in ZLMediaKit are used for dns resolution, file demultiplexing during mp4 on-demand
|
||||
* @return Background thread
|
||||
|
||||
* [AUTO-TRANSLATED:3b552537]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_pool_work();
|
||||
|
||||
@ -60,6 +83,13 @@ typedef struct mk_thread_pool_t *mk_thread_pool;
|
||||
* @param n_thread 线程个数,0时为cpu个数
|
||||
* @param priority 线程优先级,分为PRIORITY_LOWEST = 0,PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_HIGHEST
|
||||
* @return 线程池
|
||||
* Create a thread pool
|
||||
* @param name Thread pool name, for debugging
|
||||
* @param n_thread Number of threads, 0 for the number of cpus
|
||||
* @param priority Thread priority, divided into PRIORITY_LOWEST = 0,PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_HIGHEST
|
||||
* @return Thread pool
|
||||
|
||||
* [AUTO-TRANSLATED:177acea2]
|
||||
*/
|
||||
API_EXPORT mk_thread_pool API_CALL mk_thread_pool_create(const char *name, size_t n_thread, int priority);
|
||||
|
||||
@ -67,6 +97,11 @@ API_EXPORT mk_thread_pool API_CALL mk_thread_pool_create(const char *name, size_
|
||||
* 销毁线程池
|
||||
* @param pool 线程池
|
||||
* @return 0:成功
|
||||
* Destroy the thread pool
|
||||
* @param pool Thread pool
|
||||
* @return 0: Success
|
||||
|
||||
* [AUTO-TRANSLATED:1f1b3582]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_thread_pool_release(mk_thread_pool pool);
|
||||
|
||||
@ -74,9 +109,15 @@ API_EXPORT int API_CALL mk_thread_pool_release(mk_thread_pool pool);
|
||||
* 从线程池获取一个线程
|
||||
* @param pool 线程池
|
||||
* @return 线程
|
||||
* Get a thread from the thread pool
|
||||
* @param pool Thread pool
|
||||
* @return Thread
|
||||
|
||||
* [AUTO-TRANSLATED:f47de48e]
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_thread_pool(mk_thread_pool pool);
|
||||
|
||||
// /////////////////////////////////////////线程切换///////////////////////////////////////////// [AUTO-TRANSLATED:5fc795bf]
|
||||
// /////////////////////////////////////////线程切换/////////////////////////////////////////////
|
||||
typedef void (API_CALL *on_mk_async)(void *user_data);
|
||||
|
||||
@ -85,6 +126,12 @@ typedef void (API_CALL *on_mk_async)(void *user_data);
|
||||
* @param ctx 事件线程
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
* Switch to the event thread and execute asynchronously
|
||||
* @param ctx Event thread
|
||||
* @param cb Callback function
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:55773ed5]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_async_do(mk_thread ctx, on_mk_async cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_async_do2(mk_thread ctx, on_mk_async cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -95,6 +142,13 @@ API_EXPORT void API_CALL mk_async_do2(mk_thread ctx, on_mk_async cb, void *user_
|
||||
* @param ms 延时时间,单位毫秒
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
* Switch to the event thread and execute with delay
|
||||
* @param ctx Event thread
|
||||
* @param ms Delay time, in milliseconds
|
||||
* @param cb Callback function
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:35dfdb0e]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_async_do_delay(mk_thread ctx, size_t ms, on_mk_async cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_async_do_delay2(mk_thread ctx, size_t ms, on_mk_async cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -104,15 +158,26 @@ API_EXPORT void API_CALL mk_async_do_delay2(mk_thread ctx, size_t ms, on_mk_asyn
|
||||
* @param ctx 事件线程
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
* Switch to the event thread and execute synchronously
|
||||
* @param ctx Event thread
|
||||
* @param cb Callback function
|
||||
* @param user_data User data pointer
|
||||
|
||||
* [AUTO-TRANSLATED:1326dfb2]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sync_do(mk_thread ctx, on_mk_async cb, void *user_data);
|
||||
|
||||
// /////////////////////////////////////////定时器///////////////////////////////////////////// [AUTO-TRANSLATED:7f76781c]
|
||||
// /////////////////////////////////////////定时器/////////////////////////////////////////////
|
||||
typedef struct mk_timer_t *mk_timer;
|
||||
|
||||
/**
|
||||
* 定时器触发事件
|
||||
* @return 下一次触发延时(单位毫秒),返回0则不再重复
|
||||
* Timer trigger event
|
||||
* @return Next trigger delay (in milliseconds), return 0 to stop repeating
|
||||
|
||||
* [AUTO-TRANSLATED:f8846f56]
|
||||
*/
|
||||
typedef uint64_t (API_CALL *on_mk_timer)(void *user_data);
|
||||
|
||||
@ -123,6 +188,14 @@ typedef uint64_t (API_CALL *on_mk_timer)(void *user_data);
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
* @return 定时器对象
|
||||
* Create a timer
|
||||
* @param ctx Thread object
|
||||
* @param delay_ms Execution delay, in milliseconds
|
||||
* @param cb Callback function
|
||||
* @param user_data User data pointer
|
||||
* @return Timer object
|
||||
|
||||
* [AUTO-TRANSLATED:2d47864a]
|
||||
*/
|
||||
API_EXPORT mk_timer API_CALL mk_timer_create(mk_thread ctx, uint64_t delay_ms, on_mk_timer cb, void *user_data);
|
||||
API_EXPORT mk_timer API_CALL mk_timer_create2(mk_thread ctx, uint64_t delay_ms, on_mk_timer cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -130,31 +203,49 @@ API_EXPORT mk_timer API_CALL mk_timer_create2(mk_thread ctx, uint64_t delay_ms,
|
||||
/**
|
||||
* 销毁和取消定时器
|
||||
* @param ctx 定时器对象
|
||||
* Destroy and cancel the timer
|
||||
* @param ctx Timer object
|
||||
|
||||
* [AUTO-TRANSLATED:3fdb8534]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_timer_release(mk_timer ctx);
|
||||
|
||||
// /////////////////////////////////////////信号量///////////////////////////////////////////// [AUTO-TRANSLATED:f41da57a]
|
||||
// /////////////////////////////////////////信号量/////////////////////////////////////////////
|
||||
|
||||
typedef struct mk_sem_t *mk_sem;
|
||||
|
||||
/**
|
||||
* 创建信号量
|
||||
* Create a semaphore
|
||||
|
||||
* [AUTO-TRANSLATED:dcd83058]
|
||||
*/
|
||||
API_EXPORT mk_sem API_CALL mk_sem_create();
|
||||
|
||||
/**
|
||||
* 销毁信号量
|
||||
* Destroy the semaphore
|
||||
|
||||
* [AUTO-TRANSLATED:b298797b]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_release(mk_sem sem);
|
||||
|
||||
/**
|
||||
* 信号量加n
|
||||
* Increase the semaphore by n
|
||||
|
||||
* [AUTO-TRANSLATED:1f455c5d]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_post(mk_sem sem, size_t n);
|
||||
|
||||
/**
|
||||
* 信号量减1
|
||||
* @param sem
|
||||
* Decrease the semaphore by 1
|
||||
* @param sem
|
||||
|
||||
* [AUTO-TRANSLATED:626595d8]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_wait(mk_sem sem);
|
||||
|
||||
|
@ -18,12 +18,15 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//音视频轨道
|
||||
// 音视频轨道 [AUTO-TRANSLATED:cec3b225]
|
||||
// Audio and video track
|
||||
typedef struct mk_track_t *mk_track;
|
||||
//输出frame回调
|
||||
// 输出frame回调 [AUTO-TRANSLATED:4daee75b]
|
||||
// Output frame callback
|
||||
typedef void(API_CALL *on_mk_frame_out)(void *user_data, mk_frame frame);
|
||||
|
||||
//track创建参数
|
||||
// track创建参数 [AUTO-TRANSLATED:31a3c487]
|
||||
// Track creation parameters
|
||||
typedef union {
|
||||
struct {
|
||||
int width;
|
||||
@ -42,12 +45,22 @@ typedef union {
|
||||
* @param codec_id 请参考MKCodecXXX 常量定义
|
||||
* @param args 视频或音频参数
|
||||
* @return track对象引用
|
||||
* Create a track object reference
|
||||
* @param codec_id Please refer to the MKCodecXXX constant definition
|
||||
* @param args Video or audio parameters
|
||||
* @return Track object reference
|
||||
|
||||
* [AUTO-TRANSLATED:d53f3578]
|
||||
*/
|
||||
API_EXPORT mk_track API_CALL mk_track_create(int codec_id, codec_args *args);
|
||||
|
||||
/**
|
||||
* 减引用track对象
|
||||
* @param track track对象
|
||||
* Decrement the reference count of the track object
|
||||
* @param track Track object
|
||||
|
||||
* [AUTO-TRANSLATED:50d6180e]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_unref(mk_track track);
|
||||
|
||||
@ -55,36 +68,59 @@ API_EXPORT void API_CALL mk_track_unref(mk_track track);
|
||||
* 引用track对象
|
||||
* @param track track对象
|
||||
* @return 新的track引用对象
|
||||
* Increment the reference count of the track object
|
||||
* @param track Track object
|
||||
* @return New track reference object
|
||||
|
||||
* [AUTO-TRANSLATED:6492cbb1]
|
||||
*/
|
||||
API_EXPORT mk_track API_CALL mk_track_ref(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取track 编码codec类型,请参考MKCodecXXX定义
|
||||
* Get the track encoding codec type, please refer to the MKCodecXXX definition
|
||||
|
||||
* [AUTO-TRANSLATED:f90ed835]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_codec_id(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取编码codec名称
|
||||
* Get the encoding codec name
|
||||
|
||||
* [AUTO-TRANSLATED:f46d430e]
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_track_codec_name(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取比特率信息
|
||||
* Get the bitrate information
|
||||
|
||||
* [AUTO-TRANSLATED:de8b48fe]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_bit_rate(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取轨道是否已就绪,1: 已就绪,0:未就绪
|
||||
* Get whether the track is ready, 1: ready, 0: not ready
|
||||
|
||||
* [AUTO-TRANSLATED:926d1a1a]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_ready(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取累计帧数
|
||||
* Get the cumulative frame count
|
||||
|
||||
* [AUTO-TRANSLATED:c30a45c6]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_track_frames(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取时间,单位毫秒
|
||||
* Get the time, in milliseconds
|
||||
|
||||
* [AUTO-TRANSLATED:37b0e1f9]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_track_duration(mk_track track);
|
||||
|
||||
@ -93,6 +129,12 @@ API_EXPORT uint64_t API_CALL mk_track_duration(mk_track track);
|
||||
* @param track track对象
|
||||
* @param cb frame输出回调
|
||||
* @param user_data frame输出回调用户指针参数
|
||||
* Listen for frame output events
|
||||
* @param track Track object
|
||||
* @param cb Frame output callback
|
||||
* @param user_data Frame output callback user pointer parameter
|
||||
|
||||
* [AUTO-TRANSLATED:5cbd8347]
|
||||
*/
|
||||
API_EXPORT void *API_CALL mk_track_add_delegate(mk_track track, on_mk_frame_out cb, void *user_data);
|
||||
API_EXPORT void *API_CALL mk_track_add_delegate2(mk_track track, on_mk_frame_out cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -101,61 +143,99 @@ API_EXPORT void *API_CALL mk_track_add_delegate2(mk_track track, on_mk_frame_out
|
||||
* 取消frame输出事件监听
|
||||
* @param track track对象
|
||||
* @param tag mk_track_add_delegate返回值
|
||||
* Cancel the frame output event listener
|
||||
* @param track Track object
|
||||
* @param tag Return value of mk_track_add_delegate
|
||||
|
||||
* [AUTO-TRANSLATED:83a9fd9f]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_del_delegate(mk_track track, void *tag);
|
||||
|
||||
/**
|
||||
* 输入frame到track,通常你不需要调用此api
|
||||
* Input frame to track, you usually don't need to call this api
|
||||
|
||||
* [AUTO-TRANSLATED:ca3b03e8]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_input_frame(mk_track track, mk_frame frame);
|
||||
|
||||
/**
|
||||
* track是否为视频
|
||||
* Whether the track is video
|
||||
|
||||
* [AUTO-TRANSLATED:22573187]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_is_video(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频宽度
|
||||
* Get the video width
|
||||
|
||||
* [AUTO-TRANSLATED:06a849c6]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_width(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频高度
|
||||
* Get the video height
|
||||
|
||||
* [AUTO-TRANSLATED:27b5ed6e]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_height(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频帧率
|
||||
* Get the video frame rate
|
||||
|
||||
* [AUTO-TRANSLATED:3c19a388]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_fps(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频累计关键帧数
|
||||
* Get the cumulative number of video keyframes
|
||||
|
||||
* [AUTO-TRANSLATED:0e70e666]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_track_video_key_frames(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频GOP关键帧间隔
|
||||
* Get the video GOP keyframe interval
|
||||
|
||||
* [AUTO-TRANSLATED:ea8d3729]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_gop_size(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频累计关键帧间隔(毫秒)
|
||||
* Get the cumulative video keyframe interval (milliseconds)
|
||||
|
||||
* [AUTO-TRANSLATED:194b1e80]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_gop_interval_ms(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频采样率
|
||||
* Get the audio sample rate
|
||||
|
||||
* [AUTO-TRANSLATED:bf0e046b]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_rate(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频通道数
|
||||
* Get the number of audio channels
|
||||
|
||||
* [AUTO-TRANSLATED:ccb5d776]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_channel(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频位数,一般为16bit
|
||||
* Get the audio bit depth, usually 16bit
|
||||
|
||||
* [AUTO-TRANSLATED:11e36409]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_bit(mk_track track);
|
||||
|
||||
|
@ -19,17 +19,24 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//解码器对象
|
||||
// 解码器对象 [AUTO-TRANSLATED:14f75955]
|
||||
// cpp
|
||||
// Decoder object
|
||||
typedef struct mk_decoder_t *mk_decoder;
|
||||
//解码后的frame
|
||||
// 解码后的frame [AUTO-TRANSLATED:acb96f85]
|
||||
// Decoded frame
|
||||
typedef struct mk_frame_pix_t *mk_frame_pix;
|
||||
//SwsContext的包装
|
||||
// SwsContext的包装 [AUTO-TRANSLATED:4f7ae38f]
|
||||
// SwsContext wrapper
|
||||
typedef struct mk_swscale_t *mk_swscale;
|
||||
//FFmpeg原始解码帧对象
|
||||
// FFmpeg原始解码帧对象 [AUTO-TRANSLATED:ed99009b]
|
||||
// FFmpeg original decoded frame object
|
||||
typedef struct AVFrame AVFrame;
|
||||
//FFmpeg编解码器对象
|
||||
// FFmpeg编解码器对象 [AUTO-TRANSLATED:12b26186]
|
||||
// FFmpeg codec object
|
||||
typedef struct AVCodecContext AVCodecContext;
|
||||
//解码输出回调
|
||||
// 解码输出回调 [AUTO-TRANSLATED:1a380eed]
|
||||
// Decode output callback
|
||||
typedef void(API_CALL *on_mk_decode)(void *user_data, mk_frame_pix frame);
|
||||
|
||||
/**
|
||||
@ -37,6 +44,12 @@ typedef void(API_CALL *on_mk_decode)(void *user_data, mk_frame_pix frame);
|
||||
* @param track track对象
|
||||
* @param thread_num 解码线程数,0时为自动
|
||||
* @return 返回解码器对象,NULL代表失败
|
||||
* Create decoder
|
||||
* @param track track object
|
||||
* @param thread_num Number of decoding threads, 0 for automatic
|
||||
* @return Returns the decoder object, NULL indicates failure
|
||||
|
||||
* [AUTO-TRANSLATED:d01b3192]
|
||||
*/
|
||||
API_EXPORT mk_decoder API_CALL mk_decoder_create(mk_track track, int thread_num);
|
||||
|
||||
@ -47,6 +60,14 @@ API_EXPORT mk_decoder API_CALL mk_decoder_create(mk_track track, int thread_num)
|
||||
* @param codec_name_list 偏好的ffmpeg codec name列表,以NULL结尾,譬如:{"libopenh264", "h264_nvdec", NULL};
|
||||
* 在数组中越前,优先级越高;如果指定的codec不存在,或跟mk_track_codec_id类型不匹配时,则使用内部默认codec列表
|
||||
* @return 返回解码器对象,NULL代表失败
|
||||
* Create decoder
|
||||
* @param track track object
|
||||
* @param thread_num Number of decoding threads, 0 for automatic
|
||||
* @param codec_name_list Preferred ffmpeg codec name list, ending with NULL, for example: {"libopenh264", "h264_nvdec", NULL};
|
||||
* The higher the priority in the array, the higher the priority; if the specified codec does not exist, or does not match the mk_track_codec_id type, the internal default codec list will be used
|
||||
* @return Returns the decoder object, NULL indicates failure
|
||||
|
||||
* [AUTO-TRANSLATED:078aba31]
|
||||
*/
|
||||
API_EXPORT mk_decoder API_CALL mk_decoder_create2(mk_track track, int thread_num, const char *codec_name_list[]);
|
||||
|
||||
@ -54,6 +75,11 @@ API_EXPORT mk_decoder API_CALL mk_decoder_create2(mk_track track, int thread_num
|
||||
* 销毁解码器
|
||||
* @param ctx 解码器对象
|
||||
* @param flush_frame 是否等待所有帧解码成功
|
||||
* Destroy decoder
|
||||
* @param ctx Decoder object
|
||||
* @param flush_frame Whether to wait for all frames to be decoded successfully
|
||||
|
||||
* [AUTO-TRANSLATED:1a4d9663]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_release(mk_decoder ctx, int flush_frame);
|
||||
|
||||
@ -63,11 +89,21 @@ API_EXPORT void API_CALL mk_decoder_release(mk_decoder ctx, int flush_frame);
|
||||
* @param frame 帧对象
|
||||
* @param async 是否异步解码
|
||||
* @param enable_merge 是否合并帧解码,有些情况下,需要把时间戳相同的slice合并输入到解码器才能解码
|
||||
* Decode audio and video frames
|
||||
* @param ctx Decoder
|
||||
* @param frame Frame object
|
||||
* @param async Whether to decode asynchronously
|
||||
* @param enable_merge Whether to merge frame decoding, in some cases, it is necessary to merge slices with the same timestamp into the decoder before decoding
|
||||
|
||||
* [AUTO-TRANSLATED:87df4c4d]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_decode(mk_decoder ctx, mk_frame frame, int async, int enable_merge);
|
||||
|
||||
/**
|
||||
* 设置异步解码最大帧缓存积压数限制
|
||||
* Set the maximum frame cache backlog limit for asynchronous decoding
|
||||
|
||||
* [AUTO-TRANSLATED:1e3e413d]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_set_max_async_frame_size(mk_decoder ctx, size_t size);
|
||||
|
||||
@ -76,6 +112,12 @@ API_EXPORT void API_CALL mk_decoder_set_max_async_frame_size(mk_decoder ctx, siz
|
||||
* @param ctx 解码器
|
||||
* @param cb 回调函数
|
||||
* @param user_data 回调函数用户指针参数
|
||||
* Set decode output callback
|
||||
* @param ctx Decoder
|
||||
* @param cb Callback function
|
||||
* @param user_data User pointer parameter of the callback function
|
||||
|
||||
* [AUTO-TRANSLATED:a90f8764]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_set_cb(mk_decoder ctx, on_mk_decode cb, void *user_data);
|
||||
API_EXPORT void API_CALL mk_decoder_set_cb2(mk_decoder ctx, on_mk_decode cb, void *user_data, on_user_data_free user_data_free);
|
||||
@ -83,6 +125,10 @@ API_EXPORT void API_CALL mk_decoder_set_cb2(mk_decoder ctx, on_mk_decode cb, voi
|
||||
/**
|
||||
* 获取FFmpeg原始AVCodecContext对象
|
||||
* @param ctx 解码器
|
||||
* Get the FFmpeg original AVCodecContext object
|
||||
* @param ctx Decoder
|
||||
|
||||
* [AUTO-TRANSLATED:73ed5496]
|
||||
*/
|
||||
API_EXPORT const AVCodecContext* API_CALL mk_decoder_get_context(mk_decoder ctx);
|
||||
|
||||
@ -92,12 +138,21 @@ API_EXPORT const AVCodecContext* API_CALL mk_decoder_get_context(mk_decoder ctx)
|
||||
* 创建解码帧mk_frame_pix新引用
|
||||
* @param frame 原始引用
|
||||
* @return 新引用
|
||||
* Create a new reference to the mk_frame_pix decoding frame
|
||||
* @param frame Original reference
|
||||
* @return New reference
|
||||
|
||||
* [AUTO-TRANSLATED:ca58ab5d]
|
||||
*/
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_ref(mk_frame_pix frame);
|
||||
|
||||
/**
|
||||
* 解码帧mk_frame_pix减引用
|
||||
* @param frame 原始引用
|
||||
* Decrease the reference of the decoding frame mk_frame_pix
|
||||
* @param frame Original reference
|
||||
|
||||
* [AUTO-TRANSLATED:1581d0a9]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_pix_unref(mk_frame_pix frame);
|
||||
|
||||
@ -105,6 +160,11 @@ API_EXPORT void API_CALL mk_frame_pix_unref(mk_frame_pix frame);
|
||||
* 从FFmpeg AVFrame转换为mk_frame_pix
|
||||
* @param frame FFmpeg AVFrame
|
||||
* @return mk_frame_pix对象
|
||||
* Convert from FFmpeg AVFrame to mk_frame_pix
|
||||
* @param frame FFmpeg AVFrame
|
||||
* @return mk_frame_pix object
|
||||
|
||||
* [AUTO-TRANSLATED:adfb43d5]
|
||||
*/
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_av_frame(AVFrame *frame);
|
||||
|
||||
@ -114,6 +174,13 @@ API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_av_frame(AVFrame *frame);
|
||||
* @param line_size 平面数据line size
|
||||
* @param plane 数据平面个数
|
||||
* @return mk_frame_pix对象
|
||||
* Create a mk_frame_pix object without memory copy
|
||||
* @param plane_data Multiple plane data, get its data pointer through mk_buffer_get_data
|
||||
* @param line_size Plane data line size
|
||||
* @param plane Number of data planes
|
||||
* @return mk_frame_pix object
|
||||
|
||||
* [AUTO-TRANSLATED:b720d2e2]
|
||||
*/
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_buffer(mk_buffer plane_data[], int line_size[], int plane);
|
||||
|
||||
@ -121,6 +188,11 @@ API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_buffer(mk_buffer plane_data[]
|
||||
* 获取FFmpeg AVFrame对象
|
||||
* @param frame 解码帧mk_frame_pix
|
||||
* @return FFmpeg AVFrame对象
|
||||
* Get the FFmpeg AVFrame object
|
||||
* @param frame Decoded frame mk_frame_pix
|
||||
* @return FFmpeg AVFrame object
|
||||
|
||||
* [AUTO-TRANSLATED:03142bdc]
|
||||
*/
|
||||
API_EXPORT AVFrame* API_CALL mk_frame_pix_get_av_frame(mk_frame_pix frame);
|
||||
|
||||
@ -132,12 +204,23 @@ API_EXPORT AVFrame* API_CALL mk_frame_pix_get_av_frame(mk_frame_pix frame);
|
||||
* @param width 目标宽度,置0时,则与输入时一致
|
||||
* @param height 目标高度,置0时,则与输入时一致
|
||||
* @return SwsContext wrapper 实例
|
||||
* Create an instance of the ffmpeg SwsContext wrapper
|
||||
* @param output AVPixelFormat type, AV_PIX_FMT_BGR24==3
|
||||
* @param width Target width, set to 0, then it is the same as the input
|
||||
* @param height Target height, set to 0, then it is the same as the input
|
||||
* @return SwsContext wrapper instance
|
||||
|
||||
* [AUTO-TRANSLATED:417474cb]
|
||||
*/
|
||||
API_EXPORT mk_swscale mk_swscale_create(int output, int width, int height);
|
||||
|
||||
/**
|
||||
* 释放ffmpeg SwsContext wrapper实例
|
||||
* @param ctx SwsContext wrapper实例
|
||||
* Release the ffmpeg SwsContext wrapper instance
|
||||
* @param ctx SwsContext wrapper instance
|
||||
|
||||
* [AUTO-TRANSLATED:8eaaea2f]
|
||||
*/
|
||||
API_EXPORT void mk_swscale_release(mk_swscale ctx);
|
||||
|
||||
@ -147,6 +230,13 @@ API_EXPORT void mk_swscale_release(mk_swscale ctx);
|
||||
* @param frame pix frame
|
||||
* @param out 转换后存放的数据指针,用户需要确保提前申请并大小足够
|
||||
* @return sws_scale()返回值:the height of the output slice
|
||||
* Use SwsContext to convert pix format
|
||||
* @param ctx SwsContext wrapper instance
|
||||
* @param frame pix frame
|
||||
* @param out Data pointer to store the converted data, the user needs to ensure that the application is applied in advance and the size is sufficient
|
||||
* @return sws_scale() return value: the height of the output slice
|
||||
|
||||
* [AUTO-TRANSLATED:3018afe4]
|
||||
*/
|
||||
API_EXPORT int mk_swscale_input_frame(mk_swscale ctx, mk_frame_pix frame, uint8_t *out);
|
||||
|
||||
@ -155,6 +245,13 @@ API_EXPORT int mk_swscale_input_frame(mk_swscale ctx, mk_frame_pix frame, uint8_
|
||||
* @param ctx SwsContext wrapper实例
|
||||
* @param frame pix frame
|
||||
* @return 新的pix frame对象,需要使用mk_frame_pix_unref销毁
|
||||
* Use SwsContext to convert pix format
|
||||
* @param ctx SwsContext wrapper instance
|
||||
* @param frame pix frame
|
||||
* @return New pix frame object, needs to be destroyed using mk_frame_pix_unref
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:5b4e98a3]
|
||||
*/
|
||||
API_EXPORT mk_frame_pix mk_swscale_input_frame2(mk_swscale ctx, mk_frame_pix frame);
|
||||
|
||||
|
@ -20,12 +20,19 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* 释放mk api内部malloc的资源
|
||||
* Release resources allocated by mk api internally
|
||||
|
||||
* [AUTO-TRANSLATED:92ecfef5]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_free(void *ptr);
|
||||
|
||||
/**
|
||||
* 获取本程序可执行文件路径
|
||||
* @return 文件路径,使用完后需要自己mk_free
|
||||
* Get the path of the executable file of this program
|
||||
* @return File path, need to be mk_free after use
|
||||
|
||||
* [AUTO-TRANSLATED:5f1fae7f]
|
||||
*/
|
||||
API_EXPORT char* API_CALL mk_util_get_exe_path();
|
||||
|
||||
@ -33,12 +40,21 @@ API_EXPORT char* API_CALL mk_util_get_exe_path();
|
||||
* 获取本程序可执行文件相同目录下文件的绝对路径
|
||||
* @param relative_path 同目录下文件的路径相对,可以为null
|
||||
* @return 文件路径,使用完后需要自己mk_free
|
||||
* Get the absolute path of the file in the same directory as the executable file of this program
|
||||
* @param relative_path The path of the file in the same directory, can be null
|
||||
* @return File path, need to be mk_free after use
|
||||
|
||||
* [AUTO-TRANSLATED:80442e8e]
|
||||
*/
|
||||
API_EXPORT char* API_CALL mk_util_get_exe_dir(const char *relative_path);
|
||||
|
||||
/**
|
||||
* 获取unix标准的系统时间戳
|
||||
* @return 当前系统时间戳
|
||||
* Get the Unix standard system timestamp
|
||||
* @return Current system timestamp
|
||||
|
||||
* [AUTO-TRANSLATED:feddaa5b]
|
||||
*/
|
||||
API_EXPORT uint64_t API_CALL mk_util_get_current_millisecond();
|
||||
|
||||
@ -46,6 +62,11 @@ API_EXPORT uint64_t API_CALL mk_util_get_current_millisecond();
|
||||
* 获取时间字符串
|
||||
* @param fmt 时间格式,譬如%Y-%m-%d %H:%M:%S
|
||||
* @return 时间字符串,使用完后需要自己mk_free
|
||||
* Get the time string
|
||||
* @param fmt Time format, such as %Y-%m-%d %H:%M:%S
|
||||
* @return Time string, need to be mk_free after use
|
||||
|
||||
* [AUTO-TRANSLATED:c5a6c984]
|
||||
*/
|
||||
API_EXPORT char* API_CALL mk_util_get_current_time_string(const char *fmt);
|
||||
|
||||
@ -54,6 +75,12 @@ API_EXPORT char* API_CALL mk_util_get_current_time_string(const char *fmt);
|
||||
* @param buf 二进制数据
|
||||
* @param len 数据长度
|
||||
* @return 可打印的调试信息,使用完后需要自己mk_free
|
||||
* Print binary data as string
|
||||
* @param buf Binary data
|
||||
* @param len Data length
|
||||
* @return Printable debug information, need to be mk_free after use
|
||||
|
||||
* [AUTO-TRANSLATED:5b76b3a5]
|
||||
*/
|
||||
API_EXPORT char* API_CALL mk_util_hex_dump(const void *buf, int len);
|
||||
|
||||
@ -62,12 +89,19 @@ typedef struct mk_ini_t *mk_ini;
|
||||
|
||||
/**
|
||||
* 创建ini配置对象
|
||||
* Create ini configuration object
|
||||
|
||||
* [AUTO-TRANSLATED:b8ce40cc]
|
||||
*/
|
||||
API_EXPORT mk_ini API_CALL mk_ini_create();
|
||||
|
||||
/**
|
||||
* 返回全局默认ini配置
|
||||
* @return 全局默认ini配置,请勿用mk_ini_release释放它
|
||||
* Return the global default ini configuration
|
||||
* @return Global default ini configuration, do not use mk_ini_release to release it
|
||||
|
||||
* [AUTO-TRANSLATED:057ea031]
|
||||
*/
|
||||
API_EXPORT mk_ini API_CALL mk_ini_default();
|
||||
|
||||
@ -75,6 +109,11 @@ API_EXPORT mk_ini API_CALL mk_ini_default();
|
||||
* 加载ini配置文件内容
|
||||
* @param ini ini对象
|
||||
* @param str 配置文件内容
|
||||
* Load ini configuration file content
|
||||
* @param ini Ini object
|
||||
* @param str Configuration file content
|
||||
|
||||
* [AUTO-TRANSLATED:b9366be5]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_ini_load_string(mk_ini ini, const char *str);
|
||||
|
||||
@ -82,11 +121,19 @@ API_EXPORT void API_CALL mk_ini_load_string(mk_ini ini, const char *str);
|
||||
* 加载ini配置文件
|
||||
* @param ini ini对象
|
||||
* @param file 配置文件路径
|
||||
* Load ini configuration file
|
||||
* @param ini Ini object
|
||||
* @param file Configuration file path
|
||||
|
||||
* [AUTO-TRANSLATED:688e0471]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_ini_load_file(mk_ini ini, const char *file);
|
||||
|
||||
/**
|
||||
* 销毁ini配置对象
|
||||
* Destroy ini configuration object
|
||||
|
||||
* [AUTO-TRANSLATED:b6286ab8]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_ini_release(mk_ini ini);
|
||||
|
||||
@ -95,6 +142,12 @@ API_EXPORT void API_CALL mk_ini_release(mk_ini ini);
|
||||
* @param ini 配置对象
|
||||
* @param key 配置名,两段式,如:field.key
|
||||
* @param value 配置值
|
||||
* Add or overwrite configuration item
|
||||
* @param ini Configuration object
|
||||
* @param key Configuration name, two-part, such as: field.key
|
||||
* @param value Configuration value
|
||||
|
||||
* [AUTO-TRANSLATED:1b2c8bfa]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_ini_set_option(mk_ini ini, const char *key, const char *value);
|
||||
API_EXPORT void API_CALL mk_ini_set_option_int(mk_ini ini, const char *key, int value);
|
||||
@ -104,6 +157,12 @@ API_EXPORT void API_CALL mk_ini_set_option_int(mk_ini ini, const char *key, int
|
||||
* @param ini 配置对象
|
||||
* @param key 配置名,两段式,如:field.key
|
||||
* @return 配置不存在返回NULL,否则返回配置值
|
||||
* Get configuration item
|
||||
* @param ini Configuration object
|
||||
* @param key Configuration name, two-part, such as: field.key
|
||||
* @return NULL if the configuration does not exist, otherwise return the configuration value
|
||||
|
||||
* [AUTO-TRANSLATED:4df4bc65]
|
||||
*/
|
||||
API_EXPORT const char *API_CALL mk_ini_get_option(mk_ini ini, const char *key);
|
||||
|
||||
@ -112,6 +171,12 @@ API_EXPORT const char *API_CALL mk_ini_get_option(mk_ini ini, const char *key);
|
||||
* @param ini 配置对象
|
||||
* @param key 配置名,两段式,如:field.key
|
||||
* @return 1: 成功,0: 该配置不存在
|
||||
* Delete configuration item
|
||||
* @param ini Configuration object
|
||||
* @param key Configuration name, two-part, such as: field.key
|
||||
* @return 1: Success, 0: The configuration does not exist
|
||||
|
||||
* [AUTO-TRANSLATED:dbbbdca3]
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_ini_del_option(mk_ini ini, const char *key);
|
||||
|
||||
@ -119,6 +184,11 @@ API_EXPORT int API_CALL mk_ini_del_option(mk_ini ini, const char *key);
|
||||
* 导出为配置文件内容
|
||||
* @param ini 配置对象
|
||||
* @return 配置文件内容字符串,用完后需要自行mk_free
|
||||
* Export to configuration file content
|
||||
* @param ini Configuration object
|
||||
* @return Configuration file content string, need to be mk_free after use
|
||||
|
||||
* [AUTO-TRANSLATED:94620b68]
|
||||
*/
|
||||
API_EXPORT char *API_CALL mk_ini_dump_string(mk_ini ini);
|
||||
|
||||
@ -126,8 +196,14 @@ API_EXPORT char *API_CALL mk_ini_dump_string(mk_ini ini);
|
||||
* 导出配置文件到文件
|
||||
* @param ini 配置对象
|
||||
* @param file 配置文件路径
|
||||
* Export configuration file to file
|
||||
* @param ini Configuration object
|
||||
* @param file Configuration file path
|
||||
|
||||
* [AUTO-TRANSLATED:8fac58af]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file);
|
||||
// /////////////////////////////////////////统计///////////////////////////////////////////// [AUTO-TRANSLATED:964becb9]
|
||||
// /////////////////////////////////////////统计/////////////////////////////////////////////
|
||||
|
||||
typedef void(API_CALL *on_mk_get_statistic_cb)(void *user_data, mk_ini ini);
|
||||
@ -135,9 +211,14 @@ typedef void(API_CALL *on_mk_get_statistic_cb)(void *user_data, mk_ini ini);
|
||||
/**
|
||||
* 获取内存数据统计
|
||||
* @param ini 存放统计结果
|
||||
* Get memory data statistics
|
||||
* @param ini Store statistical results
|
||||
|
||||
* [AUTO-TRANSLATED:48d8035c]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb cb, void *user_data, on_user_data_free free_cb);
|
||||
|
||||
// /////////////////////////////////////////日志///////////////////////////////////////////// [AUTO-TRANSLATED:b1bd4de8]
|
||||
// /////////////////////////////////////////日志/////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
@ -148,10 +229,20 @@ API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb cb, void *user_
|
||||
* @param line __LINE__
|
||||
* @param fmt printf类型的格式控制字符串
|
||||
* @param ... 不定长参数
|
||||
* Print log
|
||||
* @param level Log level, support 0~4
|
||||
* @param file __FILE__
|
||||
* @param function __FUNCTION__
|
||||
* @param line __LINE__
|
||||
* @param fmt printf type format control string
|
||||
* @param ... Variable length parameters
|
||||
|
||||
* [AUTO-TRANSLATED:f19956e7]
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_log_printf(int level, const char *file, const char *function, int line, const char *fmt, ...);
|
||||
|
||||
// 以下宏可以替换printf使用
|
||||
// 以下宏可以替换printf使用 [AUTO-TRANSLATED:73b59437]
|
||||
// The following macros can replace printf
|
||||
#define log_printf(lev, ...) mk_log_printf(lev, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#define log_trace(...) log_printf(0, ##__VA_ARGS__)
|
||||
#define log_debug(...) log_printf(1, ##__VA_ARGS__)
|
||||
|
@ -93,20 +93,24 @@ API_EXPORT void API_CALL mk_env_init2(int thread_num,
|
||||
int ssl_is_path,
|
||||
const char *ssl,
|
||||
const char *ssl_pwd) {
|
||||
//确保只初始化一次
|
||||
// 确保只初始化一次 [AUTO-TRANSLATED:e4b32b0f]
|
||||
// Ensure initialization only happens once
|
||||
static onceToken token([&]() {
|
||||
if (log_mask & LOG_CONSOLE) {
|
||||
//控制台日志
|
||||
// 控制台日志 [AUTO-TRANSLATED:5c00e83f]
|
||||
// Console log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", (LogLevel) log_level));
|
||||
}
|
||||
|
||||
if (log_mask & LOG_CALLBACK) {
|
||||
//广播日志
|
||||
// 广播日志 [AUTO-TRANSLATED:67556df8]
|
||||
// Broadcast log
|
||||
Logger::Instance().add(std::make_shared<EventChannel>("EventChannel", (LogLevel) log_level));
|
||||
}
|
||||
|
||||
if (log_mask & LOG_FILE) {
|
||||
//日志文件
|
||||
// 日志文件 [AUTO-TRANSLATED:afacc934]
|
||||
// Log file
|
||||
auto channel = std::make_shared<FileChannel>("FileChannel",
|
||||
log_file_path ? File::absolutePath("", log_file_path) :
|
||||
exeDir() + "log/", (LogLevel) log_level);
|
||||
@ -114,15 +118,18 @@ API_EXPORT void API_CALL mk_env_init2(int thread_num,
|
||||
Logger::Instance().add(channel);
|
||||
}
|
||||
|
||||
//异步日志线程
|
||||
// 异步日志线程 [AUTO-TRANSLATED:1cc193a1]
|
||||
// Asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//设置线程数
|
||||
// 设置线程数 [AUTO-TRANSLATED:22ec5cc9]
|
||||
// Set thread count
|
||||
EventPollerPool::setPoolSize(thread_num);
|
||||
WorkThreadPool::setPoolSize(thread_num);
|
||||
|
||||
if (ini && ini[0]) {
|
||||
//设置配置文件
|
||||
// 设置配置文件 [AUTO-TRANSLATED:2216856d]
|
||||
// Set configuration file
|
||||
if (ini_is_path) {
|
||||
try {
|
||||
mINI::Instance().parseFile(ini);
|
||||
@ -136,7 +143,8 @@ API_EXPORT void API_CALL mk_env_init2(int thread_num,
|
||||
}
|
||||
|
||||
if (ssl && ssl[0]) {
|
||||
//设置ssl证书
|
||||
// 设置ssl证书 [AUTO-TRANSLATED:e441027c]
|
||||
// Set SSL certificate
|
||||
SSL_Initor::Instance().loadCertificate(ssl, true, ssl_pwd ? ssl_pwd : "", ssl_is_path);
|
||||
}
|
||||
});
|
||||
@ -157,7 +165,8 @@ API_EXPORT void API_CALL mk_set_option(const char *key, const char *val) {
|
||||
return;
|
||||
}
|
||||
mINI::Instance()[key] = val;
|
||||
//广播配置文件热加载
|
||||
// 广播配置文件热加载 [AUTO-TRANSLATED:7ae561f3]
|
||||
// Broadcast configuration file hot reload
|
||||
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
|
||||
}
|
||||
|
||||
@ -226,7 +235,8 @@ API_EXPORT uint16_t API_CALL mk_rtmp_server_start(uint16_t port, int ssl) {
|
||||
API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port){
|
||||
#ifdef ENABLE_RTPPROXY
|
||||
try {
|
||||
//创建rtp 服务器
|
||||
// 创建rtp 服务器 [AUTO-TRANSLATED:480fda83]
|
||||
// Create RTP server
|
||||
rtpServer = std::make_shared<RtpServer>();
|
||||
rtpServer->start(port);
|
||||
return rtpServer->getPort();
|
||||
@ -244,7 +254,8 @@ API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port){
|
||||
API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port) {
|
||||
#ifdef ENABLE_WEBRTC
|
||||
try {
|
||||
//创建rtc udp服务器
|
||||
// 创建rtc udp服务器 [AUTO-TRANSLATED:9287972e]
|
||||
// Create RTC UDP server
|
||||
rtcServer_udp = std::make_shared<UdpServer>();
|
||||
rtcServer_udp->setOnCreateSocket([](const EventPoller::Ptr &poller, const Buffer::Ptr &buf, struct sockaddr *, int) {
|
||||
if (!buf) {
|
||||
@ -252,13 +263,15 @@ API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port) {
|
||||
}
|
||||
auto new_poller = WebRtcSession::queryPoller(buf);
|
||||
if (!new_poller) {
|
||||
//该数据对应的webrtc对象未找到,丢弃之
|
||||
// 该数据对应的webrtc对象未找到,丢弃之 [AUTO-TRANSLATED:d401f8cb]
|
||||
// The WebRTC object corresponding to this data was not found, discard it
|
||||
return Socket::Ptr();
|
||||
}
|
||||
return Socket::createSocket(new_poller, false);
|
||||
});
|
||||
rtcServer_udp->start<WebRtcSession>(port);
|
||||
//创建rtc tcp服务器
|
||||
// 创建rtc tcp服务器 [AUTO-TRANSLATED:1eefd92f]
|
||||
// Create RTC TCP server
|
||||
rtcServer_tcp = std::make_shared<TcpServer>();
|
||||
rtcServer_tcp->start<WebRtcSession>(rtcServer_udp->getPort());
|
||||
return rtcServer_udp->getPort();
|
||||
@ -328,7 +341,8 @@ API_EXPORT uint16_t API_CALL mk_srt_server_start(uint16_t port) {
|
||||
}
|
||||
auto new_poller = SRT::SrtSession::queryPoller(buf);
|
||||
if (!new_poller) {
|
||||
//握手第一阶段
|
||||
// 握手第一阶段 [AUTO-TRANSLATED:6b3abcd4]
|
||||
// Handshake stage one
|
||||
return Socket::createSocket(poller, false);
|
||||
}
|
||||
return Socket::createSocket(new_poller, false);
|
||||
|
@ -228,7 +228,8 @@ API_EXPORT mk_track API_CALL mk_media_source_get_track(const mk_media_source ctx
|
||||
API_EXPORT float API_CALL mk_media_source_get_track_loss(const mk_media_source ctx, const mk_track track) {
|
||||
assert(ctx);
|
||||
MediaSource *src = (MediaSource *)ctx;
|
||||
// rtp推流只有一个统计器,但是可能有多个track,如果短时间多次获取间隔丢包率,第二次会获取为-1
|
||||
// rtp推流只有一个统计器,但是可能有多个track,如果短时间多次获取间隔丢包率,第二次会获取为-1 [AUTO-TRANSLATED:b30fec2c]
|
||||
// RTP streaming has only one statistics object, but there may be multiple tracks. If the packet loss rate is obtained multiple times in a short period, the second time will be obtained as -1
|
||||
return src->getLossRate((*((Track::Ptr *)track))->getTrackType());
|
||||
}
|
||||
|
||||
@ -608,7 +609,8 @@ API_EXPORT void API_CALL mk_rtc_send_datachannel(const mk_rtc_transport ctx, uin
|
||||
std::string msg_str(msg, len);
|
||||
std::weak_ptr<WebRtcTransport> weak_trans = transport->shared_from_this();
|
||||
transport->getPoller()->async([streamId, ppid, msg_str, weak_trans]() {
|
||||
// 切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:12d77fca]
|
||||
// Operate after switching threads
|
||||
if (auto trans = weak_trans.lock()) {
|
||||
trans->sendDatachannel(streamId, ppid, msg_str.c_str(), msg_str.size());
|
||||
}
|
||||
|
@ -45,12 +45,14 @@ H264Splitter::~H264Splitter() {
|
||||
ssize_t H264Splitter::onRecvHeader(const char *data, size_t len) {
|
||||
auto frame = Factory::getFrameFromPtr(_h265 ? CodecH265 : CodecH264, (char *)data, len, 0, 0);
|
||||
if (_have_decode_frame && (frame->decodeAble() || frame->configFrame())) {
|
||||
// 缓存中存在可解码帧,且下一帧是可解码帧或者配置帧,那么flush缓存
|
||||
// 缓存中存在可解码帧,且下一帧是可解码帧或者配置帧,那么flush缓存 [AUTO-TRANSLATED:2c52093b]
|
||||
// Flush the cache if there are decodable frames in the cache and the next frame is a decodable frame or a configuration frame.
|
||||
_cb(_buffer.data(), _buffer.size());
|
||||
_buffer.assign(data, len);
|
||||
_have_decode_frame = frame->decodeAble();
|
||||
} else {
|
||||
// 还需要缓存
|
||||
// 还需要缓存 [AUTO-TRANSLATED:a4dc19cb]
|
||||
// Still need to cache
|
||||
_buffer.append(data, len);
|
||||
_have_decode_frame = _have_decode_frame || frame->decodeAble();
|
||||
}
|
||||
@ -59,10 +61,12 @@ ssize_t H264Splitter::onRecvHeader(const char *data, size_t len) {
|
||||
|
||||
const char *H264Splitter::onSearchPacketTail(const char *data, size_t len) {
|
||||
for (size_t i = 2; len > 2 && i < len - 2; ++i) {
|
||||
//判断0x00 00 01
|
||||
// 判断0x00 00 01 [AUTO-TRANSLATED:afa3d4c2]
|
||||
// Determine if it is 0x00 00 01
|
||||
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
|
||||
if (i > 0 && data[i - 1] == 0) {
|
||||
//找到0x00 00 00 01
|
||||
// 找到0x00 00 00 01 [AUTO-TRANSLATED:96a10021]
|
||||
// Find 0x00 00 00 01
|
||||
return data + i - 1;
|
||||
}
|
||||
return data + i;
|
||||
|
@ -21,7 +21,8 @@ public:
|
||||
using Ptr = std::shared_ptr<MediaHelper>;
|
||||
MediaHelper(const char *vhost, const char *app, const char *stream, float duration, const ProtocolOption &option) {
|
||||
_poller = EventPollerPool::Instance().getPoller();
|
||||
// 在poller线程中创建DevChannel(MultiMediaSourceMuxer)对象,确保严格的线程安全限制
|
||||
// 在poller线程中创建DevChannel(MultiMediaSourceMuxer)对象,确保严格的线程安全限制 [AUTO-TRANSLATED:d5063d7a]
|
||||
// Create a DevChannel (MultiMediaSourceMuxer) object in the poller thread to ensure strict thread safety restrictions
|
||||
auto tuple = MediaTuple{vhost, app, stream};
|
||||
_poller->sync([&]() { _channel = std::make_shared<DevChannel>(tuple, duration, option); });
|
||||
}
|
||||
@ -58,14 +59,17 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
// 通知其停止推流
|
||||
// 通知其停止推流 [AUTO-TRANSLATED:d69d10d8]
|
||||
// Notify it to stop streaming
|
||||
bool close(MediaSource &sender) override {
|
||||
if (!_on_close) {
|
||||
//未设置回调,没法关闭
|
||||
// 未设置回调,没法关闭 [AUTO-TRANSLATED:2c1423fe]
|
||||
// No callback is set, so it cannot be closed
|
||||
WarnL << "请使用mk_media_set_on_close函数设置回调函数!";
|
||||
return false;
|
||||
}
|
||||
//请在回调中调用mk_media_release函数释放资源,否则MediaSource::close()操作不会生效
|
||||
// 请在回调中调用mk_media_release函数释放资源,否则MediaSource::close()操作不会生效 [AUTO-TRANSLATED:da067eb0]
|
||||
// Please call the mk_media_release function to release resources in the callback, otherwise the MediaSource::close() operation will not take effect
|
||||
_on_close(_on_close_data.get());
|
||||
WarnL << "close media: " << sender.getUrl();
|
||||
return true;
|
||||
@ -78,7 +82,8 @@ protected:
|
||||
return _on_seek(_on_seek_data.get(), stamp);
|
||||
}
|
||||
|
||||
// 通知暂停或恢复
|
||||
// 通知暂停或恢复 [AUTO-TRANSLATED:ee3c219f]
|
||||
// Notify pause or resume
|
||||
bool pause(MediaSource &sender, bool pause) override {
|
||||
if (!_on_pause) {
|
||||
return false;
|
||||
@ -86,7 +91,8 @@ protected:
|
||||
return _on_pause(_on_pause_data.get(), pause);
|
||||
}
|
||||
|
||||
//通知倍数播放
|
||||
// 通知倍数播放 [AUTO-TRANSLATED:12e66e3f]
|
||||
// Notify playback speed
|
||||
bool speed(MediaSource &sender, float speed) override {
|
||||
if (!_on_speed) {
|
||||
return false;
|
||||
@ -297,7 +303,8 @@ API_EXPORT void API_CALL mk_media_start_send_rtp2(mk_media ctx, const char *dst_
|
||||
args.close_delay_ms = 30 * 1000;
|
||||
args.con_type = (mediakit::MediaSourceEvent::SendRtpArgs::ConType)con_type;
|
||||
|
||||
// sender参数无用
|
||||
// sender参数无用 [AUTO-TRANSLATED:21590ae5]
|
||||
// The sender parameter is useless
|
||||
auto ref = *obj;
|
||||
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
(*obj)->getChannel()->getOwnerPoller(MediaSource::NullMediaSource())->async([args, ref, cb, ptr]() {
|
||||
@ -335,7 +342,8 @@ API_EXPORT void API_CALL mk_media_start_send_rtp4(mk_media ctx, const char *dst_
|
||||
args.close_delay_ms = (*ini_ptr)["close_delay_ms"].empty() ? 30000 : (*ini_ptr)["close_delay_ms"].as<int>();
|
||||
args.rtcp_timeout_ms = (*ini_ptr)["rtcp_timeout_ms"].empty() ? 30000 : (*ini_ptr)["rtcp_timeout_ms"].as<int>();
|
||||
args.rtcp_send_interval_ms = (*ini_ptr)["rtcp_send_interval_ms"].empty() ? 5000 : (*ini_ptr)["rtcp_send_interval_ms"].as<int>();
|
||||
// sender参数无用
|
||||
// sender参数无用 [AUTO-TRANSLATED:21590ae5]
|
||||
// The sender parameter is useless
|
||||
auto ref = *obj;
|
||||
std::shared_ptr<void> ptr(
|
||||
user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
@ -351,7 +359,8 @@ API_EXPORT void API_CALL mk_media_start_send_rtp4(mk_media ctx, const char *dst_
|
||||
API_EXPORT void API_CALL mk_media_stop_send_rtp(mk_media ctx, const char *ssrc) {
|
||||
assert(ctx);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *)ctx;
|
||||
// sender参数无用
|
||||
// sender参数无用 [AUTO-TRANSLATED:21590ae5]
|
||||
// The sender parameter is useless
|
||||
auto ref = *obj;
|
||||
string ssrc_str = ssrc ? ssrc : "";
|
||||
(*obj)->getChannel()->getOwnerPoller(MediaSource::NullMediaSource())->async([ref, ssrc_str]() {
|
||||
|
@ -57,14 +57,16 @@ public:
|
||||
void onEvent(bool is_shutdown, const SockException &ex){
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
if (is_shutdown) {
|
||||
//播放中断
|
||||
// 播放中断 [AUTO-TRANSLATED:9b841156]
|
||||
// Play interrupted
|
||||
if (_on_shutdown) {
|
||||
_on_shutdown(_on_shutdown_data.get(), ex.getErrCode(), ex.what(), nullptr, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//播放结果
|
||||
// 播放结果 [AUTO-TRANSLATED:15f1e8fe]
|
||||
// Play result
|
||||
if (_on_play) {
|
||||
auto cpp_tracks = _player->getTracks(false);
|
||||
mk_track tracks[TrackMax] = {nullptr};
|
||||
@ -118,7 +120,8 @@ API_EXPORT void API_CALL mk_player_set_option(mk_player ctx,const char* key,cons
|
||||
auto player = obj.getPlayer();
|
||||
string key_str(key), val_str(val);
|
||||
player->getPoller()->async([key_str,val_str,player](){
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
(*player)[key_str] = val_str;
|
||||
});
|
||||
}
|
||||
@ -128,7 +131,8 @@ API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url) {
|
||||
auto player = obj.getPlayer();
|
||||
string url_str(url);
|
||||
player->getPoller()->async([url_str,player](){
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
player->play(url_str);
|
||||
});
|
||||
}
|
||||
@ -138,7 +142,8 @@ API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) {
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto player = obj.getPlayer();
|
||||
player->getPoller()->async([pause,player](){
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
player->pause(pause);
|
||||
});
|
||||
}
|
||||
@ -148,7 +153,8 @@ API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed) {
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx);
|
||||
auto player = obj.getPlayer();
|
||||
player->getPoller()->async([speed, player]() {
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
player->speed(speed);
|
||||
});
|
||||
}
|
||||
@ -158,7 +164,8 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) {
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto player = obj.getPlayer();
|
||||
player->getPoller()->async([progress,player](){
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
player->seekTo(progress);
|
||||
});
|
||||
}
|
||||
@ -168,7 +175,8 @@ API_EXPORT void API_CALL mk_player_seekto_pos(mk_player ctx, int seek_pos) {
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx);
|
||||
auto player = obj.getPlayer();
|
||||
player->getPoller()->async([seek_pos, player]() {
|
||||
//切换线程后再操作
|
||||
// 切换线程后再操作 [AUTO-TRANSLATED:b8f01c71]
|
||||
// Operate after switching threads
|
||||
player->seekTo((uint32_t) seek_pos);
|
||||
});
|
||||
}
|
||||
|
@ -53,7 +53,8 @@ API_EXPORT void API_CALL mk_proxy_player_set_option(mk_proxy_player ctx, const c
|
||||
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *) ctx);
|
||||
std::string key_str(key), val_str(val);
|
||||
obj->getPoller()->async([obj,key_str,val_str](){
|
||||
//切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:b78259f9]
|
||||
// Switch threads and then operate
|
||||
(*obj)[key_str] = val_str;
|
||||
});
|
||||
}
|
||||
@ -63,7 +64,8 @@ API_EXPORT void API_CALL mk_proxy_player_play(mk_proxy_player ctx, const char *u
|
||||
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *) ctx);
|
||||
std::string url_str(url);
|
||||
obj->getPoller()->async([obj,url_str](){
|
||||
//切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:b78259f9]
|
||||
// Switch threads and then operate
|
||||
obj->play(url_str);
|
||||
});
|
||||
}
|
||||
@ -77,7 +79,8 @@ API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_m
|
||||
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *)ctx);
|
||||
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
obj->getPoller()->async([obj, cb, ptr]() {
|
||||
// 切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:bae49fee]
|
||||
// Switch threads and then operate
|
||||
obj->setOnClose([cb, ptr](const SockException &ex) {
|
||||
if (cb) {
|
||||
cb(ptr.get(), ex.getErrCode(), ex.what(), ex.getCustomCode());
|
||||
@ -91,7 +94,8 @@ API_EXPORT void API_CALL mk_proxy_player_set_on_play_result(mk_proxy_player ctx,
|
||||
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *)ctx);
|
||||
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
obj->getPoller()->async([obj, cb, ptr]() {
|
||||
// 切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:bae49fee]
|
||||
// Switch threads and then operate
|
||||
obj->setPlayCallbackOnce([cb, ptr](const SockException &ex) {
|
||||
if (cb) {
|
||||
cb(ptr.get(), ex.getErrCode(), ex.what(), ex.getCustomCode());
|
||||
|
@ -39,7 +39,8 @@ API_EXPORT void API_CALL mk_pusher_set_option(mk_pusher ctx, const char *key, co
|
||||
MediaPusher::Ptr &obj = *((MediaPusher::Ptr *)ctx);
|
||||
std::string key_str(key), val_str(val);
|
||||
obj->getPoller()->async([obj,key_str,val_str](){
|
||||
//切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:b78259f9]
|
||||
// Switch threads and then operate
|
||||
(*obj)[key_str] = val_str;
|
||||
});
|
||||
}
|
||||
@ -49,7 +50,8 @@ API_EXPORT void API_CALL mk_pusher_publish(mk_pusher ctx,const char *url){
|
||||
MediaPusher::Ptr &obj = *((MediaPusher::Ptr *)ctx);
|
||||
std::string url_str(url);
|
||||
obj->getPoller()->async([obj,url_str](){
|
||||
//切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:b78259f9]
|
||||
// Switch threads and then operate
|
||||
obj->publish(url_str);
|
||||
});
|
||||
}
|
||||
@ -63,7 +65,8 @@ API_EXPORT void API_CALL mk_pusher_set_on_result2(mk_pusher ctx, on_mk_push_even
|
||||
MediaPusher::Ptr &obj = *((MediaPusher::Ptr *)ctx);
|
||||
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
obj->getPoller()->async([obj, cb, ptr]() {
|
||||
// 切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:bae49fee]
|
||||
// Switch threads and then operate
|
||||
obj->setOnPublished([cb, ptr](const SockException &ex) { cb(ptr.get(), ex.getErrCode(), ex.what()); });
|
||||
});
|
||||
}
|
||||
@ -77,7 +80,8 @@ API_EXPORT void API_CALL mk_pusher_set_on_shutdown2(mk_pusher ctx, on_mk_push_ev
|
||||
MediaPusher::Ptr &obj = *((MediaPusher::Ptr *)ctx);
|
||||
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
||||
obj->getPoller()->async([obj, cb, ptr]() {
|
||||
// 切换线程再操作
|
||||
// 切换线程再操作 [AUTO-TRANSLATED:bae49fee]
|
||||
// Switch threads and then operate
|
||||
obj->setOnShutdown([cb, ptr](const SockException &ex) { cb(ptr.get(), ex.getErrCode(), ex.what()); });
|
||||
});
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *v
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////hls/mp4录制/////////////////////////////////////////////
|
||||
// /////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// [AUTO-TRANSLATED:99c61c68]
|
||||
// /////////////////////////////////////////hls/mp4 recording/////////////////////////////////////////////
|
||||
|
||||
static inline bool isRecording(Recorder::type type, const string &vhost, const string &app, const string &stream_id){
|
||||
auto src = MediaSource::find(vhost, app, stream_id);
|
||||
|
@ -242,11 +242,13 @@ API_EXPORT uint16_t API_CALL mk_tcp_server_start(uint16_t port, mk_tcp_type type
|
||||
s_tcp_server[type]->start<SessionWithSSL<SessionForC> >(port);
|
||||
break;
|
||||
case mk_type_ws:
|
||||
//此处你也可以修改WebSocketHeader::BINARY
|
||||
// 此处你也可以修改WebSocketHeader::BINARY [AUTO-TRANSLATED:706abaab]
|
||||
// You can also modify WebSocketHeader::BINARY here
|
||||
s_tcp_server[type]->start<WebSocketSession<SessionForC, HttpSession, WebSocketHeader::TEXT> >(port);
|
||||
break;
|
||||
case mk_type_wss:
|
||||
//此处你也可以修改WebSocketHeader::BINARY
|
||||
// 此处你也可以修改WebSocketHeader::BINARY [AUTO-TRANSLATED:706abaab]
|
||||
// You can also modify WebSocketHeader::BINARY here
|
||||
s_tcp_server[type]->start<WebSocketSession<SessionForC, HttpsSession, WebSocketHeader::TEXT> >(port);
|
||||
break;
|
||||
default:
|
||||
@ -307,10 +309,12 @@ TcpClientForC::Ptr *mk_tcp_client_create_l(mk_tcp_client_events *events, mk_tcp_
|
||||
case mk_type_ssl:
|
||||
return (TcpClientForC::Ptr *)new std::shared_ptr<SessionWithSSL<TcpClientForC> >(new SessionWithSSL<TcpClientForC>(events));
|
||||
case mk_type_ws:
|
||||
//此处你也可以修改WebSocketHeader::BINARY
|
||||
// 此处你也可以修改WebSocketHeader::BINARY [AUTO-TRANSLATED:706abaab]
|
||||
// You can also modify WebSocketHeader::BINARY here
|
||||
return (TcpClientForC::Ptr *)new std::shared_ptr<WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, false> >(new WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, false>(events));
|
||||
case mk_type_wss:
|
||||
//此处你也可以修改WebSocketHeader::BINARY
|
||||
// 此处你也可以修改WebSocketHeader::BINARY [AUTO-TRANSLATED:706abaab]
|
||||
// You can also modify WebSocketHeader::BINARY
|
||||
return (TcpClientForC::Ptr *)new std::shared_ptr<WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, true> >(new WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, true>(events));
|
||||
default:
|
||||
return nullptr;
|
||||
|
@ -134,7 +134,8 @@ API_EXPORT void API_CALL mk_timer_release(mk_timer ctx){
|
||||
class WorkThreadPoolForC : public TaskExecutorGetterImp {
|
||||
public:
|
||||
WorkThreadPoolForC(const char *name, size_t n_thread, int priority) {
|
||||
//最低优先级
|
||||
// 最低优先级 [AUTO-TRANSLATED:cd1f0dbc]
|
||||
// Lowest priority
|
||||
addPoller(name, n_thread, (ThreadPool::Priority) priority, false);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ API_EXPORT mk_ini API_CALL mk_ini_default() {
|
||||
|
||||
static void emit_ini_file_reload(mk_ini ini) {
|
||||
if (ini == mk_ini_default()) {
|
||||
// 广播配置文件热加载
|
||||
// 广播配置文件热加载 [AUTO-TRANSLATED:86a0c1be]
|
||||
// Broadcast configuration hot reload
|
||||
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
|
||||
}
|
||||
}
|
||||
@ -223,7 +224,8 @@ API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *use
|
||||
(*obj).emplace(prefix + pr.first, std::move(pr.second));
|
||||
}
|
||||
}
|
||||
// 触发回调
|
||||
// 触发回调 [AUTO-TRANSLATED:ae2ff258]
|
||||
// Trigger callback
|
||||
cb(*obj);
|
||||
});
|
||||
|
||||
|
@ -36,7 +36,8 @@ static void on_h264_frame(void *user_data, mk_h264_splitter splitter, const char
|
||||
}
|
||||
|
||||
|
||||
//按照json转义规则转义webrtc answer sdp
|
||||
// 按照json转义规则转义webrtc answer sdp [AUTO-TRANSLATED:b9373d68]
|
||||
// Escape the webrtc answer sdp according to json escape rules
|
||||
static char *escape_string(const char *ptr){
|
||||
char *escaped = malloc(2 * strlen(ptr));
|
||||
char *ptr_escaped = escaped;
|
||||
@ -108,8 +109,16 @@ static void on_mk_webrtc_get_answer_sdp_func(void *user_data, const char *answer
|
||||
* @param invoker 执行该invoker返回http回复
|
||||
* @param consumed 置1则说明我们要处理该事件
|
||||
* @param sender http客户端相关信息
|
||||
* Receive http api request broadcast (including GET/POST)
|
||||
* @param parser http request content object
|
||||
* @param invoker Execute this invoker to return http reply
|
||||
* @param consumed Set to 1 if we want to handle this event
|
||||
* @param sender http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:39435e52]
|
||||
*/
|
||||
//测试url : http://127.0.0.1/api/test
|
||||
// 测试url : http://127.0.0.1/api/test [AUTO-TRANSLATED:4776d7a3]
|
||||
// Test url: http://127.0.0.1/api/test
|
||||
void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
const mk_http_response_invoker invoker,
|
||||
int *consumed,
|
||||
@ -119,7 +128,8 @@ void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
*consumed = 1;
|
||||
|
||||
if (strcmp(url, "/index/api/webrtc") == 0) {
|
||||
//拦截api: /index/api/webrtc
|
||||
// 拦截api: /index/api/webrtc [AUTO-TRANSLATED:1db21d1c]
|
||||
// Intercept api: /index/api/webrtc
|
||||
char rtc_url[1024];
|
||||
snprintf(rtc_url, sizeof(rtc_url), "rtc://%s/%s/%s?%s", mk_parser_get_header(parser, "Host"),
|
||||
mk_parser_get_url_param(parser, "app"), mk_parser_get_url_param(parser, "stream"),
|
||||
@ -179,7 +189,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
||||
//h264的codec
|
||||
// h264的codec [AUTO-TRANSLATED:940c6a32]
|
||||
// h264 codec
|
||||
//mk_media_init_video(media, 0, 0, 0, 0, 2 * 104 * 1024);
|
||||
codec_args v_args = {0};
|
||||
mk_track v_track = mk_track_create(MKCodecH264, &v_args);
|
||||
@ -187,7 +198,8 @@ int main(int argc, char *argv[]) {
|
||||
mk_media_init_complete(media);
|
||||
mk_track_unref(v_track);
|
||||
|
||||
//创建h264分帧器
|
||||
// 创建h264分帧器 [AUTO-TRANSLATED:5775837d]
|
||||
// Create h264 frame splitter
|
||||
mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media, 0);
|
||||
signal(SIGINT, s_on_exit);// 设置退出信号
|
||||
|
||||
@ -197,7 +209,8 @@ int main(int argc, char *argv[]) {
|
||||
if (size > 0) {
|
||||
mk_h264_splitter_input_data(splitter, buf, size);
|
||||
} else {
|
||||
//文件读完了,重新开始
|
||||
// 文件读完了,重新开始 [AUTO-TRANSLATED:035fb238]
|
||||
// File read finished, start again
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
@ -69,23 +69,27 @@ void API_CALL on_regist(void *user_data, mk_media_source sender, int regist) {
|
||||
Context *ptr = (Context *)user_data;
|
||||
const char *schema = mk_media_source_get_schema(sender);
|
||||
if (strstr(ptr->url, schema) != ptr->url) {
|
||||
// 协议匹配失败
|
||||
// 协议匹配失败 [AUTO-TRANSLATED:436784d0]
|
||||
// Protocol matching failed
|
||||
return;
|
||||
}
|
||||
|
||||
if (!regist) {
|
||||
// 注销
|
||||
// 注销 [AUTO-TRANSLATED:ebc5be28]
|
||||
// Log out
|
||||
if (ptr->pusher) {
|
||||
mk_pusher_release(ptr->pusher);
|
||||
ptr->pusher = NULL;
|
||||
}
|
||||
} else {
|
||||
// 注册
|
||||
// 注册 [AUTO-TRANSLATED:e2df30a6]
|
||||
// Register
|
||||
if (!ptr->pusher) {
|
||||
ptr->pusher = mk_pusher_create_src(sender);
|
||||
mk_pusher_set_on_result2(ptr->pusher, on_push_result, ptr, NULL);
|
||||
mk_pusher_set_on_shutdown2(ptr->pusher, on_push_shutdown, ptr, NULL);
|
||||
// 开始推流
|
||||
// 开始推流 [AUTO-TRANSLATED:df3972ff]
|
||||
// Start streaming
|
||||
mk_pusher_publish(ptr->pusher, ptr->url);
|
||||
}
|
||||
}
|
||||
@ -115,7 +119,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
||||
// h264的codec
|
||||
// h264的codec [AUTO-TRANSLATED:e840179e]
|
||||
// h264 codec
|
||||
codec_args v_args = { 0 };
|
||||
mk_track v_track = mk_track_create(MKCodecH264, &v_args);
|
||||
mk_media_init_track(media, v_track);
|
||||
@ -128,7 +133,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
mk_media_set_on_regist2(media, on_regist, ctx, release_context);
|
||||
|
||||
// 创建h264分帧器
|
||||
// 创建h264分帧器 [AUTO-TRANSLATED:72254159]
|
||||
// Create h264 frame splitter
|
||||
mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media, 0);
|
||||
signal(SIGINT, s_on_exit); // 设置退出信号
|
||||
signal(SIGTERM, s_on_exit); // 设置退出信号
|
||||
@ -139,7 +145,8 @@ int main(int argc, char *argv[]) {
|
||||
if (size > 0) {
|
||||
mk_h264_splitter_input_data(splitter, buf, size);
|
||||
} else {
|
||||
// 文件读完了,重新开始
|
||||
// 文件读完了,重新开始 [AUTO-TRANSLATED:ffffe75c]
|
||||
// File read finished, start again
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,8 @@ int main(int argc, char *argv[]) {
|
||||
mk_http_requester_set_cb(requester, on_requester_complete, &ctx);
|
||||
mk_http_requester_start(requester, "http://www.baidu.com/baidu", 10);
|
||||
|
||||
//等待http请求完毕
|
||||
// 等待http请求完毕 [AUTO-TRANSLATED:0c1d7dea]
|
||||
// Wait for the HTTP request to complete
|
||||
mk_sem_wait(sem);
|
||||
|
||||
mk_sem_release(sem);
|
||||
|
@ -33,14 +33,16 @@ void API_CALL on_frame_decode(void *user_data, mk_frame_pix frame) {
|
||||
int align = 32;
|
||||
size_t pixel_size = 3;
|
||||
size_t raw_linesize = w * pixel_size;
|
||||
// 对齐后的宽度
|
||||
// 对齐后的宽度 [AUTO-TRANSLATED:f9bfe888]
|
||||
// Aligned width
|
||||
size_t aligned_linesize = (raw_linesize + align - 1) & ~(align - 1);
|
||||
size_t total_size = aligned_linesize * h;
|
||||
uint8_t* brg24 = malloc(total_size);
|
||||
mk_swscale_input_frame(ctx->swscale, frame, brg24);
|
||||
free(brg24);
|
||||
#else
|
||||
//todo 此处转换为opencv对象
|
||||
// todo 此处转换为opencv对象 [AUTO-TRANSLATED:37358ee1]
|
||||
// todo Convert to opencv object here
|
||||
cv::Mat *mat = new cv::Mat();
|
||||
mat->create(h, w, CV_8UC3);
|
||||
mk_swscale_input_frame(ctx->swscale, frame, (uint8_t *) mat->data);
|
||||
@ -60,7 +62,8 @@ void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *e
|
||||
log_info("got video track: %s", mk_track_codec_name(tracks[i]));
|
||||
ctx->video_decoder = mk_decoder_create(tracks[i], 0);
|
||||
mk_decoder_set_cb(ctx->video_decoder, on_frame_decode, user_data);
|
||||
//监听track数据回调
|
||||
// 监听track数据回调 [AUTO-TRANSLATED:8295ebf6]
|
||||
// Listen to track data callback
|
||||
mk_track_add_delegate(tracks[i], on_track_frame_out, user_data);
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ void API_CALL on_mk_media_source_regist_func(void *user_data, mk_media_source se
|
||||
Context *ctx = (Context *) user_data;
|
||||
const char *schema = mk_media_source_get_schema(sender);
|
||||
if (strncmp(schema, ctx->push_url, strlen(schema)) == 0) {
|
||||
//判断是否为推流协议相关的流注册或注销事件
|
||||
// 判断是否为推流协议相关的流注册或注销事件 [AUTO-TRANSLATED:00a88a17]
|
||||
// Determine if it is a stream registration or deregistration event related to the streaming protocol
|
||||
release_pusher(&(ctx->pusher));
|
||||
if (regist) {
|
||||
ctx->pusher = mk_pusher_create_src(sender);
|
||||
@ -131,17 +132,20 @@ int main(int argc, char *argv[]){
|
||||
return -1;
|
||||
}
|
||||
|
||||
//可以通过
|
||||
// 可以通过 [AUTO-TRANSLATED:9a320d61]
|
||||
// Can be achieved through
|
||||
//rtmp://127.0.0.1/live/test
|
||||
//rtsp://127.0.0.1/live/test
|
||||
//播放mk_media的数据
|
||||
// 播放mk_media的数据 [AUTO-TRANSLATED:623dc58f]
|
||||
// Playing the data of mk_media
|
||||
mk_rtsp_server_start(554, 0);
|
||||
mk_rtmp_server_start(1935, 0);
|
||||
|
||||
Context *ctx = (Context *) malloc(sizeof(Context));
|
||||
memset(ctx, 0, sizeof(Context));
|
||||
|
||||
//推流给自己测试,当然也可以推流给其他服务器测试
|
||||
// 推流给自己测试,当然也可以推流给其他服务器测试 [AUTO-TRANSLATED:616e4dc2]
|
||||
// Stream to yourself for testing, of course, you can also stream to other servers for testing
|
||||
context_start(ctx, argv[1], argv[2]);
|
||||
|
||||
log_info("enter any key to exit");
|
||||
|
@ -17,6 +17,11 @@
|
||||
* 注册或反注册MediaSource事件广播
|
||||
* @param regist 注册为1,注销为0
|
||||
* @param sender 该MediaSource对象
|
||||
* Register or unregister MediaSource event broadcast
|
||||
* @param regist Register as 1, unregister as 0
|
||||
* @param sender The MediaSource object
|
||||
|
||||
* [AUTO-TRANSLATED:8bb75918]
|
||||
*/
|
||||
void API_CALL on_mk_media_changed(int regist,
|
||||
const mk_media_source sender) {
|
||||
@ -34,6 +39,13 @@ void API_CALL on_mk_media_changed(int regist,
|
||||
* @param url_info 推流url相关信息
|
||||
* @param invoker 执行invoker返回鉴权结果
|
||||
* @param sender 该tcp客户端相关信息
|
||||
* Receive rtsp/rtmp push stream event broadcast, control push stream authentication through this event
|
||||
* @see mk_publish_auth_invoker_do
|
||||
* @param url_info Push stream url related information
|
||||
* @param invoker Execute invoker to return authentication result
|
||||
* @param sender The tcp client related information
|
||||
|
||||
* [AUTO-TRANSLATED:72053c81]
|
||||
*/
|
||||
void API_CALL on_mk_media_publish(const mk_media_info url_info,
|
||||
const mk_publish_auth_invoker invoker,
|
||||
@ -52,7 +64,8 @@ void API_CALL on_mk_media_publish(const mk_media_info url_info,
|
||||
mk_media_info_get_stream(url_info),
|
||||
mk_media_info_get_params(url_info));
|
||||
|
||||
//允许推流,并且允许转hls/mp4
|
||||
// 允许推流,并且允许转hls/mp4 [AUTO-TRANSLATED:4b2d0e4e]
|
||||
// Allow push stream, and allow to convert to hls/mp4
|
||||
mk_publish_auth_invoker_do(invoker, NULL, 1, 1);
|
||||
}
|
||||
|
||||
@ -62,6 +75,13 @@ void API_CALL on_mk_media_publish(const mk_media_info url_info,
|
||||
* @param url_info 播放url相关信息
|
||||
* @param invoker 执行invoker返回鉴权结果
|
||||
* @param sender 播放客户端相关信息
|
||||
* Play rtsp/rtmp/http-flv/hls event broadcast, control playback authentication through this event
|
||||
* @see mk_auth_invoker_do
|
||||
* @param url_info Play url related information
|
||||
* @param invoker Execute invoker to return authentication result
|
||||
* @param sender Play client related information
|
||||
|
||||
* [AUTO-TRANSLATED:fc351667]
|
||||
*/
|
||||
void API_CALL on_mk_media_play(const mk_media_info url_info,
|
||||
const mk_auth_invoker invoker,
|
||||
@ -81,7 +101,8 @@ void API_CALL on_mk_media_play(const mk_media_info url_info,
|
||||
mk_media_info_get_stream(url_info),
|
||||
mk_media_info_get_params(url_info));
|
||||
|
||||
//允许播放
|
||||
// 允许播放 [AUTO-TRANSLATED:b940f821]
|
||||
// Allow playback
|
||||
mk_auth_invoker_do(invoker, NULL);
|
||||
}
|
||||
|
||||
@ -91,6 +112,13 @@ void API_CALL on_mk_media_play(const mk_media_info url_info,
|
||||
* @param sender 播放客户端相关信息
|
||||
* @return 1 直接关闭
|
||||
* 0 等待流注册
|
||||
* This event will be broadcast after the stream is not found. Please pull the stream or other methods to generate the stream after listening to this event, so that you can pull the stream on demand
|
||||
* @param url_info Play url related information
|
||||
* @param sender Play client related information
|
||||
* @return 1 Close directly
|
||||
* 0 Wait for stream registration
|
||||
|
||||
* [AUTO-TRANSLATED:71caa7d8]
|
||||
*/
|
||||
int API_CALL on_mk_media_not_found(const mk_media_info url_info,
|
||||
const mk_sock_info sender) {
|
||||
@ -113,6 +141,10 @@ int API_CALL on_mk_media_not_found(const mk_media_info url_info,
|
||||
/**
|
||||
* 某个流无人消费时触发,目的为了实现无人观看时主动断开拉流等业务逻辑
|
||||
* @param sender 该MediaSource对象
|
||||
* Triggered when no one consumes a certain stream, the purpose is to achieve business logic such as actively disconnecting the pull stream when no one is watching
|
||||
* @param sender The MediaSource object
|
||||
|
||||
* [AUTO-TRANSLATED:d2881c87]
|
||||
*/
|
||||
void API_CALL on_mk_media_no_reader(const mk_media_source sender) {
|
||||
log_printf(LOG_LEV,
|
||||
@ -123,7 +155,8 @@ void API_CALL on_mk_media_no_reader(const mk_media_source sender) {
|
||||
mk_media_source_get_stream(sender));
|
||||
}
|
||||
|
||||
//按照json转义规则转义webrtc answer sdp
|
||||
// 按照json转义规则转义webrtc answer sdp [AUTO-TRANSLATED:b9373d68]
|
||||
// Escape webrtc answer sdp according to json escape rules
|
||||
static char *escape_string(const char *ptr){
|
||||
char *escaped = malloc(2 * strlen(ptr));
|
||||
char *ptr_escaped = escaped;
|
||||
@ -203,8 +236,16 @@ void API_CALL on_get_statistic_cb(void *user_data, mk_ini ini) {
|
||||
* @param invoker 执行该invoker返回http回复
|
||||
* @param consumed 置1则说明我们要处理该事件
|
||||
* @param sender http客户端相关信息
|
||||
* Receive http api request broadcast (including GET/POST)
|
||||
* @param parser Http request content object
|
||||
* @param invoker Execute this invoker to return http reply
|
||||
* @param consumed Set to 1 if we want to handle this event
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:39435e52]
|
||||
*/
|
||||
//测试url : http://127.0.0.1/api/test
|
||||
// 测试url : http://127.0.0.1/api/test [AUTO-TRANSLATED:4776d7a3]
|
||||
// Test url : http://127.0.0.1/api/test
|
||||
void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
const mk_http_response_invoker invoker,
|
||||
int *consumed,
|
||||
@ -230,7 +271,8 @@ void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
const char *url = mk_parser_get_url(parser);
|
||||
*consumed = 1;
|
||||
|
||||
//拦截api: /api/test
|
||||
// 拦截api: /api/test [AUTO-TRANSLATED:262baadf]
|
||||
// Intercept api: /api/test
|
||||
if (strcmp(url, "/api/test") == 0) {
|
||||
const char *response_header[] = { "Content-Type", "text/html", NULL };
|
||||
const char *content = "<html>"
|
||||
@ -247,7 +289,8 @@ void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
mk_http_response_invoker_do(invoker, 200, response_header, body);
|
||||
mk_http_body_release(body);
|
||||
} else if (strcmp(url, "/index/api/webrtc") == 0) {
|
||||
//拦截api: /index/api/webrtc
|
||||
// 拦截api: /index/api/webrtc [AUTO-TRANSLATED:1db21d1c]
|
||||
// Intercept api: /index/api/webrtc
|
||||
char rtc_url[1024];
|
||||
snprintf(rtc_url, sizeof(rtc_url), "rtc://%s/%s/%s?%s", mk_parser_get_header(parser, "Host"),
|
||||
mk_parser_get_url_param(parser, "app"), mk_parser_get_url_param(parser, "stream"),
|
||||
@ -256,7 +299,8 @@ void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
mk_webrtc_get_answer_sdp(mk_http_response_invoker_clone(invoker), on_mk_webrtc_get_answer_sdp_func,
|
||||
mk_parser_get_url_param(parser, "type"), mk_parser_get_content(parser, NULL), rtc_url);
|
||||
} else if (strcmp(url, "/index/api/getStatistic") == 0) {
|
||||
//拦截api: /index/api/webrtc
|
||||
// 拦截api: /index/api/webrtc [AUTO-TRANSLATED:1db21d1c]
|
||||
// Intercept api: /index/api/webrtc
|
||||
mk_get_statistic(on_get_statistic_cb, mk_http_response_invoker_clone(invoker), (on_user_data_free) mk_http_response_invoker_clone_release);
|
||||
} else {
|
||||
*consumed = 0;
|
||||
@ -271,6 +315,14 @@ void API_CALL on_mk_http_request(const mk_parser parser,
|
||||
* @param is_dir path是否为文件夹
|
||||
* @param invoker 执行invoker返回本次访问文件的结果
|
||||
* @param sender http客户端相关信息
|
||||
* In the http file server, receive the broadcast of http access to files or directories, control the access permission of http directory through this event
|
||||
* @param parser Http request content object
|
||||
* @param path File absolute path
|
||||
* @param is_dir Whether path is a folder
|
||||
* @param invoker Execute invoker to return the result of accessing the file this time
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:2db5fc1e]
|
||||
*/
|
||||
void API_CALL on_mk_http_access(const mk_parser parser,
|
||||
const char *path,
|
||||
@ -296,7 +348,8 @@ void API_CALL on_mk_http_access(const mk_parser parser,
|
||||
mk_parser_get_header(parser,"User-Agent"),
|
||||
mk_parser_get_content(parser,NULL));
|
||||
|
||||
//有访问权限,每次访问文件都需要鉴权
|
||||
// 有访问权限,每次访问文件都需要鉴权 [AUTO-TRANSLATED:6ade8f21]
|
||||
// Has access permission, each access to the file needs authentication
|
||||
mk_http_access_path_invoker_do(invoker, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
@ -306,6 +359,13 @@ void API_CALL on_mk_http_access(const mk_parser parser,
|
||||
* @param parser http请求内容对象
|
||||
* @param path 文件绝对路径,覆盖之可以重定向到其他文件
|
||||
* @param sender http客户端相关信息
|
||||
* In the http file server, receive the broadcast before http access to files or directories, through this event you can control the mapping of http url to file path
|
||||
* By overriding the path parameter in this event, you can achieve the purpose of selecting different http root directories according to virtual hosts or apps
|
||||
* @param parser Http request content object
|
||||
* @param path File absolute path, override it to redirect to other files
|
||||
* @param sender Http client related information
|
||||
|
||||
* [AUTO-TRANSLATED:e166f6cb]
|
||||
*/
|
||||
void API_CALL on_mk_http_before_access(const mk_parser parser,
|
||||
char *path,
|
||||
@ -328,7 +388,8 @@ void API_CALL on_mk_http_before_access(const mk_parser parser,
|
||||
mk_parser_get_tail(parser),
|
||||
mk_parser_get_header(parser, "User-Agent"),
|
||||
mk_parser_get_content(parser,NULL));
|
||||
//覆盖path的值可以重定向文件
|
||||
// 覆盖path的值可以重定向文件 [AUTO-TRANSLATED:7b03ed02]
|
||||
// Overriding the value of path can redirect files
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,6 +397,12 @@ void API_CALL on_mk_http_before_access(const mk_parser parser,
|
||||
* @param url_info 请求rtsp url相关信息
|
||||
* @param invoker 执行invoker返回是否需要rtsp专属认证
|
||||
* @param sender rtsp客户端相关信息
|
||||
* Does this rtsp stream need authentication? If so, call invoker and pass in realm, otherwise pass in empty realm
|
||||
* @param url_info Request rtsp url related information
|
||||
* @param invoker Execute invoker to return whether rtsp exclusive authentication is required
|
||||
* @param sender Rtsp client related information
|
||||
|
||||
* [AUTO-TRANSLATED:3308f34e]
|
||||
*/
|
||||
void API_CALL on_mk_rtsp_get_realm(const mk_media_info url_info,
|
||||
const mk_rtsp_get_realm_invoker invoker,
|
||||
@ -354,7 +421,8 @@ void API_CALL on_mk_rtsp_get_realm(const mk_media_info url_info,
|
||||
mk_media_info_get_stream(url_info),
|
||||
mk_media_info_get_params(url_info));
|
||||
|
||||
//rtsp播放默认鉴权
|
||||
// rtsp播放默认鉴权 [AUTO-TRANSLATED:3a820721]
|
||||
// Rtsp playback default authentication
|
||||
mk_rtsp_get_realm_invoker_do(invoker, "zlmediakit");
|
||||
}
|
||||
|
||||
@ -367,6 +435,16 @@ void API_CALL on_mk_rtsp_get_realm(const mk_media_info url_info,
|
||||
* @param must_no_encrypt 如果为1,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
|
||||
* @param invoker 执行invoker返回rtsp专属认证的密码
|
||||
* @param sender rtsp客户端信息
|
||||
* Request authentication user password event, user_name is the username, must_no_encrypt if it is 1, then you must provide plain text password (because it is base64 authentication method at this time), otherwise it will lead to authentication failure
|
||||
* After getting the password, please call invoker and enter the corresponding type of password and password type, invoker will match the password when executing
|
||||
* @param url_info Request rtsp url related information
|
||||
* @param realm Rtsp authentication realm
|
||||
* @param user_name Rtsp authentication username
|
||||
* @param must_no_encrypt If it is 1, then you must provide plain text password (because it is base64 authentication method at this time), otherwise it will lead to authentication failure
|
||||
* @param invoker Execute invoker to return the password of rtsp exclusive authentication
|
||||
* @param sender Rtsp client information
|
||||
|
||||
* [AUTO-TRANSLATED:28391926]
|
||||
*/
|
||||
void API_CALL on_mk_rtsp_auth(const mk_media_info url_info,
|
||||
const char *realm,
|
||||
@ -391,12 +469,16 @@ void API_CALL on_mk_rtsp_auth(const mk_media_info url_info,
|
||||
mk_media_info_get_params(url_info),
|
||||
realm,user_name,(int)must_no_encrypt);
|
||||
|
||||
//rtsp播放用户名跟密码一致
|
||||
// rtsp播放用户名跟密码一致 [AUTO-TRANSLATED:31cc5970]
|
||||
// Rtsp playback username and password are consistent
|
||||
mk_rtsp_auth_invoker_do(invoker,0,user_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 录制mp4分片文件成功后广播
|
||||
* Broadcast after recording mp4 fragment file successfully
|
||||
|
||||
* [AUTO-TRANSLATED:0fdeba0d]
|
||||
*/
|
||||
void API_CALL on_mk_record_mp4(const mk_record_info mp4) {
|
||||
log_printf(LOG_LEV,
|
||||
@ -424,6 +506,9 @@ void API_CALL on_mk_record_mp4(const mk_record_info mp4) {
|
||||
|
||||
/**
|
||||
* shell登录鉴权
|
||||
* Shell login authentication
|
||||
|
||||
* [AUTO-TRANSLATED:cc20f95e]
|
||||
*/
|
||||
void API_CALL on_mk_shell_login(const char *user_name,
|
||||
const char *passwd,
|
||||
@ -438,7 +523,8 @@ void API_CALL on_mk_shell_login(const char *user_name,
|
||||
mk_sock_info_peer_ip(sender,ip + 32),
|
||||
mk_sock_info_peer_port(sender),
|
||||
user_name, passwd);
|
||||
//允许登录shell
|
||||
// 允许登录shell [AUTO-TRANSLATED:64a9b374]
|
||||
// Allow login shell
|
||||
mk_auth_invoker_do(invoker, NULL);
|
||||
}
|
||||
|
||||
@ -450,6 +536,15 @@ void API_CALL on_mk_shell_login(const char *user_name,
|
||||
* @param is_player 客户端是否为播放器
|
||||
* @param peer_ip 客户端ip
|
||||
* @param peer_port 客户端端口号
|
||||
* Stop rtsp/rtmp/http-flv session after traffic report event broadcast
|
||||
* @param url_info Play url related information
|
||||
* @param total_bytes Total traffic consumed up and down, unit is byte
|
||||
* @param total_seconds The duration of this tcp session, unit is second
|
||||
* @param is_player Whether the client is a player
|
||||
* @param peer_ip Client ip
|
||||
* @param peer_port Client port number
|
||||
|
||||
* [AUTO-TRANSLATED:6757a1c3]
|
||||
*/
|
||||
void API_CALL on_mk_flow_report(const mk_media_info url_info,
|
||||
size_t total_bytes,
|
||||
|
@ -14,18 +14,24 @@
|
||||
#include "mk_mediakit.h"
|
||||
|
||||
#define LOG_LEV 4
|
||||
//修改此宏,可以选择协议类型
|
||||
// 修改此宏,可以选择协议类型 [AUTO-TRANSLATED:7a3e6a3a]
|
||||
// Modify this macro to choose the protocol type
|
||||
#define TCP_TYPE mk_type_ws
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct {
|
||||
mk_tcp_session _session;
|
||||
//下面你可以夹杂你的私货数据
|
||||
// 下面你可以夹杂你的私货数据 [AUTO-TRANSLATED:99451203]
|
||||
// You can insert your private data below
|
||||
char your_some_useful_data[1024];
|
||||
} tcp_session_user_data;
|
||||
/**
|
||||
* 当tcp客户端连接服务器时触发
|
||||
* @param session 会话处理对象
|
||||
* Triggered when the tcp client connects to the server
|
||||
* @param session Session processing object
|
||||
|
||||
* [AUTO-TRANSLATED:0030d1a6]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_session_create(uint16_t server_port,mk_tcp_session session){
|
||||
char ip[64];
|
||||
@ -40,6 +46,12 @@ void API_CALL on_mk_tcp_session_create(uint16_t server_port,mk_tcp_session sessi
|
||||
* @param session 会话处理对象
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* Receive data sent from the tcp client
|
||||
* @param session Session processing object
|
||||
* @param data Data pointer
|
||||
* @param len Data length
|
||||
|
||||
* [AUTO-TRANSLATED:f8f01265]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_session_data(uint16_t server_port,mk_tcp_session session, mk_buffer buffer){
|
||||
char ip[64];
|
||||
@ -55,6 +67,10 @@ void API_CALL on_mk_tcp_session_data(uint16_t server_port,mk_tcp_session session
|
||||
/**
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
* @param session 会话处理对象
|
||||
* Timer every 2 seconds, used to manage timeout tasks
|
||||
* @param session Session processing object
|
||||
|
||||
* [AUTO-TRANSLATED:f664481f]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_session_manager(uint16_t server_port,mk_tcp_session session){
|
||||
char ip[64];
|
||||
@ -67,6 +83,13 @@ void API_CALL on_mk_tcp_session_manager(uint16_t server_port,mk_tcp_session sess
|
||||
* @param session 会话处理对象
|
||||
* @param code 错误代码
|
||||
* @param msg 错误提示
|
||||
* Generally triggered by the client disconnecting tcp
|
||||
* You can call the mk_tcp_session_send_safe function in this event
|
||||
* @param session Session processing object
|
||||
* @param code Error code
|
||||
* @param msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:62628263]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_session_disconnect(uint16_t server_port,mk_tcp_session session,int code,const char *msg){
|
||||
char ip[64];
|
||||
@ -78,7 +101,8 @@ void API_CALL on_mk_tcp_session_disconnect(uint16_t server_port,mk_tcp_session s
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct {
|
||||
mk_tcp_client client;
|
||||
//下面你可以夹杂你的私货数据
|
||||
// 下面你可以夹杂你的私货数据 [AUTO-TRANSLATED:99451203]
|
||||
// You can insert your private data below
|
||||
char your_some_useful_data[1024];
|
||||
int count;
|
||||
} tcp_client_user_data;
|
||||
@ -88,11 +112,18 @@ typedef struct {
|
||||
* @param client tcp客户端
|
||||
* @param code 0为连接成功,否则为失败原因
|
||||
* @param msg 连接失败错误提示
|
||||
* Callback for successful or failed connection of tcp client to server
|
||||
* @param client Tcp client
|
||||
* @param code 0 for successful connection, otherwise the reason for failure
|
||||
* @param msg Connection failure error message
|
||||
|
||||
* [AUTO-TRANSLATED:0737893b]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_client_connect(mk_tcp_client client,int code,const char *msg){
|
||||
log_printf(LOG_LEV,"connect result:%d %s",code,msg);
|
||||
if(code == 0){
|
||||
//连接上后我们发送一个hello world测试数据
|
||||
// 连接上后我们发送一个hello world测试数据 [AUTO-TRANSLATED:9eb05433]
|
||||
// After connecting, we send a hello world test data
|
||||
mk_tcp_client_send(client,"hello world",0);
|
||||
}else{
|
||||
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
|
||||
@ -107,10 +138,18 @@ void API_CALL on_mk_tcp_client_connect(mk_tcp_client client,int code,const char
|
||||
* @param client tcp客户端
|
||||
* @param code 错误代码
|
||||
* @param msg 错误提示
|
||||
* Callback for disconnection between tcp client and tcp server
|
||||
* Generally caused by eof event
|
||||
* @param client Tcp client
|
||||
* @param code Error code
|
||||
* @param msg Error message
|
||||
|
||||
* [AUTO-TRANSLATED:9cfff388]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_client_disconnect(mk_tcp_client client,int code,const char *msg){
|
||||
log_printf(LOG_LEV,"disconnect:%d %s",code,msg);
|
||||
//服务器主动断开了,我们销毁对象
|
||||
// 服务器主动断开了,我们销毁对象 [AUTO-TRANSLATED:4b142ba4]
|
||||
// The server actively disconnected, we destroy the object
|
||||
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
|
||||
mk_tcp_client_release(client);
|
||||
free(user_data);
|
||||
@ -121,6 +160,12 @@ void API_CALL on_mk_tcp_client_disconnect(mk_tcp_client client,int code,const ch
|
||||
* @param client tcp客户端
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* Receive data sent from the tcp server
|
||||
* @param client Tcp client
|
||||
* @param data Data pointer
|
||||
* @param len Data length
|
||||
|
||||
* [AUTO-TRANSLATED:d152eff2]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_client_data(mk_tcp_client client, mk_buffer buffer){
|
||||
log_printf(LOG_LEV, "data[%d]:%s", mk_buffer_get_size(buffer), mk_buffer_get_data(buffer));
|
||||
@ -129,6 +174,10 @@ void API_CALL on_mk_tcp_client_data(mk_tcp_client client, mk_buffer buffer){
|
||||
/**
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
* @param client tcp客户端
|
||||
* Timer every 2 seconds, used to manage timeout tasks
|
||||
* @param client Tcp client
|
||||
|
||||
* [AUTO-TRANSLATED:ba842db3]
|
||||
*/
|
||||
void API_CALL on_mk_tcp_client_manager(mk_tcp_client client){
|
||||
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
|
||||
@ -137,7 +186,8 @@ void API_CALL on_mk_tcp_client_manager(mk_tcp_client client){
|
||||
mk_tcp_client_send(client,buf,0);
|
||||
|
||||
if(++user_data->count == 5){
|
||||
//发送5遍后主动释放对象
|
||||
// 发送5遍后主动释放对象 [AUTO-TRANSLATED:43ce72ca]
|
||||
// Release the object after sending 5 times
|
||||
mk_tcp_client_release(client);
|
||||
free(user_data);
|
||||
}
|
||||
@ -171,7 +221,8 @@ void test_client(){
|
||||
mk_tcp_client_set_user_data(client,user_data);
|
||||
|
||||
mk_tcp_client_connect(client, "121.40.165.18", 8800, 3);
|
||||
//你可以连接127.0.0.1 80测试
|
||||
// 你可以连接127.0.0.1 80测试 [AUTO-TRANSLATED:68544f6e]
|
||||
// You can connect to 127.0.0.1 80 to test
|
||||
// mk_tcp_client_connect(client, "127.0.0.1", 80, 3);
|
||||
}
|
||||
|
||||
|
@ -37,14 +37,18 @@ public:
|
||||
unsigned int channel_configuration; // 3 uimsbf 表示声道数
|
||||
unsigned int original; // 1 bslbf
|
||||
unsigned int home; // 1 bslbf
|
||||
// 下面的为改变的参数即每一帧都不同
|
||||
// 下面的为改变的参数即每一帧都不同 [AUTO-TRANSLATED:481aa349]
|
||||
// The following are the parameters that change in each frame
|
||||
unsigned int copyright_identification_bit; // 1 bslbf
|
||||
unsigned int copyright_identification_start; // 1 bslbf
|
||||
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
|
||||
unsigned int adts_buffer_fullness; // 11 bslbf 0x7FF 说明是码率可变的码流
|
||||
// no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
|
||||
// 所以说number_of_raw_data_blocks_in_frame == 0
|
||||
// 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
|
||||
// no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧. [AUTO-TRANSLATED:3e975531]
|
||||
// no_raw_data_blocks_in_frame indicates that there are number_of_raw_data_blocks_in_frame + 1 AAC raw frames in the ADTS frame.
|
||||
// 所以说number_of_raw_data_blocks_in_frame == 0 [AUTO-TRANSLATED:1b8e9697]
|
||||
// So number_of_raw_data_blocks_in_frame == 0
|
||||
// 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) [AUTO-TRANSLATED:4a09d783]
|
||||
// means that there is one AAC data block in the ADTS frame, not that there is none. (An AAC raw frame contains 1024 samples and related data over a period of time)
|
||||
unsigned int no_raw_data_blocks_in_frame; // 2 uimsfb
|
||||
};
|
||||
|
||||
@ -203,6 +207,9 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels) {
|
||||
|
||||
/**
|
||||
* aac类型SDP
|
||||
* aac type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:c06f00b1]
|
||||
*/
|
||||
class AACSdp : public Sdp {
|
||||
public:
|
||||
@ -213,6 +220,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* Constructor
|
||||
* @param aac_cfg aac two-byte configuration description
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:6fe1f3b2]
|
||||
*/
|
||||
AACSdp(const string &aac_cfg, int payload_type, int sample_rate, int channels, int bitrate)
|
||||
: Sdp(sample_rate, payload_type) {
|
||||
@ -271,7 +286,8 @@ int AACTrack::getAudioChannel() const {
|
||||
static Frame::Ptr addADTSHeader(const Frame::Ptr &frame_in, const std::string &aac_config) {
|
||||
auto frame = FrameImp::create();
|
||||
frame->_codec_id = CodecAAC;
|
||||
// 生成adts头
|
||||
// 生成adts头 [AUTO-TRANSLATED:c285b9b0]
|
||||
// Generate adts header
|
||||
char adts_header[32] = { 0 };
|
||||
auto size = dumpAacConfig(aac_config, frame_in->size(), (uint8_t *)adts_header, sizeof(adts_header));
|
||||
CHECK(size > 0, "Invalid adts config");
|
||||
@ -290,7 +306,8 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
//有adts头,尝试分帧
|
||||
// 有adts头,尝试分帧 [AUTO-TRANSLATED:f691c4ce]
|
||||
// There is an adts header, try to frame
|
||||
int64_t dts = frame->dts();
|
||||
int64_t pts = frame->pts();
|
||||
|
||||
@ -322,13 +339,15 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
bool AACTrack::inputFrame_l(const Frame::Ptr &frame) {
|
||||
if (_cfg.empty() && frame->prefixSize()) {
|
||||
// 未获取到aac_cfg信息,根据7个字节的adts头生成aac config
|
||||
// 未获取到aac_cfg信息,根据7个字节的adts头生成aac config [AUTO-TRANSLATED:1b80f562]
|
||||
// Unable to get aac_cfg information, generate aac config based on the 7-byte adts header
|
||||
_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
|
||||
update();
|
||||
}
|
||||
|
||||
if (frame->size() > frame->prefixSize()) {
|
||||
// 除adts头外,有实际负载
|
||||
// 除adts头外,有实际负载 [AUTO-TRANSLATED:5b7c088e]
|
||||
// There is an actual payload besides the adts header
|
||||
return AudioTrack::inputFrame(frame);
|
||||
}
|
||||
return false;
|
||||
@ -377,7 +396,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
aac_cfg_str = findSubString(track->_fmtp.data(), "config=", nullptr);
|
||||
}
|
||||
if (aac_cfg_str.empty()) {
|
||||
// 如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track
|
||||
// 如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track [AUTO-TRANSLATED:995bc20d]
|
||||
// If aac config information cannot be obtained from sdp, then it cannot be obtained from rtp either, so ignore this Track
|
||||
return nullptr;
|
||||
}
|
||||
string aac_cfg;
|
||||
|
@ -19,6 +19,9 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* aac音频通道
|
||||
* AAC audio channel
|
||||
|
||||
* [AUTO-TRANSLATED:0d58b638]
|
||||
*/
|
||||
class AACTrack : public AudioTrack {
|
||||
public:
|
||||
@ -28,6 +31,10 @@ public:
|
||||
|
||||
/**
|
||||
* 通过aac extra data 构造对象
|
||||
* Construct object through AAC extra data
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:1fa035c8]
|
||||
*/
|
||||
AACTrack(const std::string &aac_cfg);
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
namespace mediakit {
|
||||
/**
|
||||
* aac Rtmp转adts类
|
||||
* aac Rtmp to adts class
|
||||
|
||||
* [AUTO-TRANSLATED:8b262ddb]
|
||||
*/
|
||||
class AACRtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@ -28,12 +31,19 @@ public:
|
||||
/**
|
||||
* 输入Rtmp并解码
|
||||
* @param rtmp Rtmp数据包
|
||||
* Input Rtmp and decode
|
||||
* @param rtmp Rtmp data packet
|
||||
|
||||
* [AUTO-TRANSLATED:43b1eae8]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* aac adts转Rtmp类
|
||||
* aac adts to Rtmp class
|
||||
|
||||
* [AUTO-TRANSLATED:2d9c53dd]
|
||||
*/
|
||||
class AACRtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@ -44,17 +54,31 @@ public:
|
||||
* 如果track不为空且包含adts头相关信息,
|
||||
* 那么inputFrame时可以不输入adts头
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case the adts header is input when inputFrame is called
|
||||
* If track is not empty and contains adts header related information,
|
||||
* then the adts header can be omitted when inputFrame is called
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:fcf8f765]
|
||||
*/
|
||||
AACRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入aac 数据,可以不带adts头
|
||||
* @param frame aac数据
|
||||
* Input aac data, can be without adts header
|
||||
* @param frame aac data
|
||||
|
||||
* [AUTO-TRANSLATED:d9f4131a]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config package
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
@ -47,7 +47,8 @@ AACRtpDecoder::AACRtpDecoder() {
|
||||
}
|
||||
|
||||
void AACRtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
// 从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 [AUTO-TRANSLATED:f85fe201]
|
||||
// Re-apply the object from the cache pool to prevent overwriting the object that has been written to the ring buffer
|
||||
_frame = FrameImp::create();
|
||||
_frame->_codec_id = CodecAAC;
|
||||
}
|
||||
@ -55,45 +56,56 @@ void AACRtpDecoder::obtainFrame() {
|
||||
bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
// 无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:2267e6ac]
|
||||
// No actual load
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stamp = rtp->getStampMS();
|
||||
// rtp数据开始部分
|
||||
// rtp数据开始部分 [AUTO-TRANSLATED:f22ebdb9]
|
||||
// Start of rtp data
|
||||
auto ptr = rtp->getPayload();
|
||||
// rtp数据末尾
|
||||
// rtp数据末尾 [AUTO-TRANSLATED:ee108f2b]
|
||||
// End of rtp data
|
||||
auto end = ptr + payload_size;
|
||||
// 首2字节表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数
|
||||
// 首2字节表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数 [AUTO-TRANSLATED:c7175051]
|
||||
// The first 2 bytes represent the number of Au-Headers, in bits, so divide by 16 to get the number of Au-Headers
|
||||
auto au_header_count = ((ptr[0] << 8) | ptr[1]) >> 4;
|
||||
if (!au_header_count) {
|
||||
// 问题issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869
|
||||
// 问题issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869 [AUTO-TRANSLATED:14be1ff8]
|
||||
// Issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869
|
||||
WarnL << "invalid aac rtp au_header_count";
|
||||
return false;
|
||||
}
|
||||
// 记录au_header起始指针
|
||||
// 记录au_header起始指针 [AUTO-TRANSLATED:b9083b72]
|
||||
// Record the starting pointer of au_header
|
||||
auto au_header_ptr = ptr + 2;
|
||||
ptr = au_header_ptr + au_header_count * 2;
|
||||
|
||||
if (end < ptr) {
|
||||
// 数据不够
|
||||
// 数据不够 [AUTO-TRANSLATED:830a2785]
|
||||
// Not enough data
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_last_dts) {
|
||||
// 记录第一个时间戳
|
||||
// 记录第一个时间戳 [AUTO-TRANSLATED:2e85b398]
|
||||
// Record the first timestamp
|
||||
_last_dts = stamp;
|
||||
}
|
||||
|
||||
// 每个audio unit时间戳增量
|
||||
// 每个audio unit时间戳增量 [AUTO-TRANSLATED:0345240c]
|
||||
// Timestamp increment for each audio unit
|
||||
auto dts_inc = static_cast<int64_t>(stamp - _last_dts) / au_header_count;
|
||||
if (dts_inc < 0 || dts_inc > 100) {
|
||||
// 时间戳增量异常,忽略
|
||||
// 时间戳增量异常,忽略 [AUTO-TRANSLATED:d2750ef8]
|
||||
// Timestamp increment anomaly, ignore
|
||||
dts_inc = 0;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < (size_t)au_header_count; ++i) {
|
||||
// 之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用
|
||||
// 之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用 [AUTO-TRANSLATED:404eb444]
|
||||
// The following 2 bytes are AU_HEADER, where the high 13 bits represent the byte length of one frame of AAC payload, and the low 3 bits are useless
|
||||
auto size = ((au_header_ptr[0] << 8) | au_header_ptr[1]) >> 3;
|
||||
auto len = std::min<int>(size, end - ptr);
|
||||
if (len <= 0) {
|
||||
@ -104,12 +116,14 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
au_header_ptr += 2;
|
||||
|
||||
if (_frame->size() >= (size_t)size) {
|
||||
// 设置当前audio unit时间戳
|
||||
// 设置当前audio unit时间戳 [AUTO-TRANSLATED:eee18d6e]
|
||||
// Set the current audio unit timestamp
|
||||
_frame->_dts = _last_dts + i * dts_inc;
|
||||
flushData();
|
||||
}
|
||||
}
|
||||
// 记录上次时间戳
|
||||
// 记录上次时间戳 [AUTO-TRANSLATED:a830d69f]
|
||||
// Record the last timestamp
|
||||
_last_dts = stamp;
|
||||
return false;
|
||||
}
|
||||
@ -117,7 +131,8 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
void AACRtpDecoder::flushData() {
|
||||
auto ptr = reinterpret_cast<const uint8_t *>(_frame->data());
|
||||
if ((ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0) && _frame->size() > ADTS_HEADER_LEN) {
|
||||
// adts头打入了rtp包,不符合规范,兼容EasyPusher的bug
|
||||
// adts头打入了rtp包,不符合规范,兼容EasyPusher的bug [AUTO-TRANSLATED:203a5ee9]
|
||||
// The adts header is inserted into the rtp packet, which is not compliant with the specification, compatible with the bug of EasyPusher
|
||||
_frame->_prefix_size = ADTS_HEADER_LEN;
|
||||
}
|
||||
RtpCodec::inputFrame(_frame);
|
||||
|
@ -17,6 +17,9 @@
|
||||
namespace mediakit {
|
||||
/**
|
||||
* aac rtp转adts类
|
||||
* aac rtp to adts class
|
||||
|
||||
* [AUTO-TRANSLATED:8ff7580f]
|
||||
*/
|
||||
class AACRtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@ -28,6 +31,11 @@ public:
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
* input rtp and decode
|
||||
* @param rtp rtp data packet
|
||||
* @param key_pos this parameter is internally forced to false, please ignore it
|
||||
|
||||
* [AUTO-TRANSLATED:2993fcbe]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
@ -43,6 +51,9 @@ private:
|
||||
|
||||
/**
|
||||
* aac adts转rtp类
|
||||
* aac adts to rtp class
|
||||
|
||||
* [AUTO-TRANSLATED:1ed889e2]
|
||||
*/
|
||||
class AACRtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@ -51,6 +62,11 @@ public:
|
||||
/**
|
||||
* 输入aac 数据,必须带dats头
|
||||
* @param frame 带dats头的aac数据
|
||||
* input aac data, must have dats header
|
||||
* @param frame aac data with dats header
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:459bba30]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
|
@ -21,6 +21,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* G711类型SDP
|
||||
* G711 type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:ea72d60a]
|
||||
*/
|
||||
class G711Sdp : public Sdp {
|
||||
public:
|
||||
@ -31,6 +34,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* G711 sampling rate is fixed at 8000
|
||||
* @param codecId G711A G711U
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:5ea4b771]
|
||||
*/
|
||||
G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate)
|
||||
: Sdp(sample_rate, payload_type) {
|
||||
@ -136,7 +147,8 @@ RtpCodec::Ptr getRtpDecoderByCodecIdU() {
|
||||
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) {
|
||||
//rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711
|
||||
// rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711 [AUTO-TRANSLATED:0ddeaafe]
|
||||
// rtmp only supports 8000/1/16 specifications for g711, but ZLMediaKit can parse other specifications of G711
|
||||
WarnL << "RTMP only support G711 with 8000/1/16, now is"
|
||||
<< audio_track->getAudioSampleRate() << "/"
|
||||
<< audio_track->getAudioChannel() << "/"
|
||||
|
@ -18,6 +18,10 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* G711音频通道
|
||||
* G711 audio channel
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:57f8bc08]
|
||||
*/
|
||||
class G711Track : public AudioTrackImp{
|
||||
public:
|
||||
|
@ -16,7 +16,8 @@ void G711RtpEncoder::setOpt(int opt, const toolkit::Any ¶m) {
|
||||
WarnL << "set g711 rtp encoder duration ms failed for " << dur;
|
||||
return;
|
||||
}
|
||||
// 向上 20ms 取整
|
||||
// 向上 20ms 取整 [AUTO-TRANSLATED:b8a9e39e]
|
||||
// Round up to the nearest 20ms
|
||||
_pkt_dur_ms = (dur + 19) / 20 * 20;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* G711 rtp编码类
|
||||
* G711 rtp encoding class
|
||||
|
||||
* [AUTO-TRANSLATED:92aa6cf3]
|
||||
*/
|
||||
class G711RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@ -28,11 +31,20 @@ public:
|
||||
* 构造函数
|
||||
* @param codec 编码类型
|
||||
* @param channels 通道数
|
||||
* Constructor
|
||||
* @param codec Encoding type
|
||||
* @param channels Number of channels
|
||||
|
||||
* [AUTO-TRANSLATED:dbbd593e]
|
||||
*/
|
||||
G711RtpEncoder(CodecId codec, uint32_t channels);
|
||||
|
||||
/**
|
||||
* 输入帧数据并编码成rtp
|
||||
* Input frame data and encode it into rtp
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:02bc9009]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
|
@ -67,24 +67,31 @@ void splitH264(
|
||||
while (true) {
|
||||
auto next_start = memfind(start, end - start, "\x00\x00\x01", 3);
|
||||
if (next_start) {
|
||||
//找到下一帧
|
||||
// 找到下一帧 [AUTO-TRANSLATED:7161f54a]
|
||||
// Find the next frame
|
||||
if (*(next_start - 1) == 0x00) {
|
||||
//这个是00 00 00 01开头
|
||||
// 这个是00 00 00 01开头 [AUTO-TRANSLATED:b0d79e9e]
|
||||
// This starts with 00 00 00 01
|
||||
next_start -= 1;
|
||||
next_prefix = 4;
|
||||
} else {
|
||||
//这个是00 00 01开头
|
||||
// 这个是00 00 01开头 [AUTO-TRANSLATED:18ae81d8]
|
||||
// This starts with 00 00 01
|
||||
next_prefix = 3;
|
||||
}
|
||||
//记得加上本帧prefix长度
|
||||
// 记得加上本帧prefix长度 [AUTO-TRANSLATED:8bde5d52]
|
||||
// Remember to add the prefix length of this frame
|
||||
cb(start - prefix, next_start - start + prefix, prefix);
|
||||
//搜索下一帧末尾的起始位置
|
||||
// 搜索下一帧末尾的起始位置 [AUTO-TRANSLATED:8976b719]
|
||||
// Search for the starting position of the end of the next frame
|
||||
start = next_start + next_prefix;
|
||||
//记录下一帧的prefix长度
|
||||
// 记录下一帧的prefix长度 [AUTO-TRANSLATED:756aee4e]
|
||||
// Record the prefix length of the next frame
|
||||
prefix = next_prefix;
|
||||
continue;
|
||||
}
|
||||
//未找到下一帧,这是最后一帧
|
||||
// 未找到下一帧,这是最后一帧 [AUTO-TRANSLATED:58365453]
|
||||
// The next frame was not found, this is the last frame
|
||||
cb(start - prefix, end - start + prefix, prefix);
|
||||
break;
|
||||
}
|
||||
@ -96,17 +103,20 @@ size_t prefixSize(const char *ptr, size_t len) {
|
||||
}
|
||||
|
||||
if (ptr[0] != 0x00 || ptr[1] != 0x00) {
|
||||
//不是0x00 00开头
|
||||
// 不是0x00 00开头 [AUTO-TRANSLATED:c406f0da]
|
||||
// Not 0x00 00 at the beginning
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ptr[2] == 0x00 && ptr[3] == 0x01) {
|
||||
//是0x00 00 00 01
|
||||
// 是0x00 00 00 01 [AUTO-TRANSLATED:70caae72]
|
||||
// It is 0x00 00 00 01
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (ptr[2] == 0x01) {
|
||||
//是0x00 00 01
|
||||
// 是0x00 00 01 [AUTO-TRANSLATED:78b4a3c9]
|
||||
// It is 0x00 00 01
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
@ -148,7 +158,8 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) {
|
||||
return inputFrame_l(frame);
|
||||
}
|
||||
|
||||
//非I/B/P帧情况下,split一下,防止多个帧粘合在一起
|
||||
// 非I/B/P帧情况下,split一下,防止多个帧粘合在一起 [AUTO-TRANSLATED:b69c6e75]
|
||||
// In the case of non-I/B/P frames, split it to prevent multiple frames from sticking together
|
||||
bool ret = false;
|
||||
splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix) {
|
||||
H264FrameInternal::Ptr sub_frame = std::make_shared<H264FrameInternal>(frame, (char *)ptr, len, prefix);
|
||||
@ -267,13 +278,15 @@ bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// 避免识别不出关键帧
|
||||
// 避免识别不出关键帧 [AUTO-TRANSLATED:8eb84679]
|
||||
// Avoid not being able to recognize keyframes
|
||||
if (_latest_is_config_frame && !frame->dropAble()) {
|
||||
if (!frame->keyFrame()) {
|
||||
const_cast<Frame::Ptr &>(frame) = std::make_shared<FrameCacheAble>(frame, true);
|
||||
}
|
||||
}
|
||||
// 判断是否是I帧, 并且如果是,那判断前面是否插入过config帧, 如果插入过就不插入了
|
||||
// 判断是否是I帧, 并且如果是,那判断前面是否插入过config帧, 如果插入过就不插入了 [AUTO-TRANSLATED:40733cd8]
|
||||
// Determine if it is an I frame, and if it is, determine if a config frame has been inserted before, and if it has been inserted, do not insert it
|
||||
if (frame->keyFrame() && !_latest_is_config_frame) {
|
||||
insertConfigFrame(frame);
|
||||
}
|
||||
@ -313,6 +326,11 @@ public:
|
||||
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
|
||||
Non Interleaved Mode = 1,// Non-interleaved Mode: 1-23,24 (STAP-A),28 (FU-A) are allowed
|
||||
Interleaved Mode = 2, // 25 (STAP-B),26 (MTAP16),27 (MTAP24),28 (EU-A),and 29 (EU-B) are allowed.
|
||||
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
|
||||
Non Interleaved Mode = 1,// Non-interleaved Mode: 1-23,24 (STAP-A),28 (FU-A) are allowed
|
||||
Interleaved Mode = 2, // 25 (STAP-B),26 (MTAP16),27 (MTAP24),28 (EU-A),and 29 (EU-B) are allowed.
|
||||
*
|
||||
* [AUTO-TRANSLATED:6166738f]
|
||||
**/
|
||||
GET_CONFIG(bool, h264_stap_a, Rtp::kH264StapA);
|
||||
_printer << "a=fmtp:" << payload_type << " packetization-mode=" << h264_stap_a << "; profile-level-id=";
|
||||
@ -365,7 +383,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
auto sps = decodeBase64(base64_SPS);
|
||||
auto pps = decodeBase64(base64_PPS);
|
||||
if (sps.empty() || pps.empty()) {
|
||||
//如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps [AUTO-TRANSLATED:60f03d45]
|
||||
// If there is no sps/pps in the sdp, then it may be possible to recover the sps/pps in the subsequent rtp
|
||||
return std::make_shared<H264Track>();
|
||||
}
|
||||
return std::make_shared<H264Track>(sps, pps, 0, 0);
|
||||
|
@ -68,24 +68,35 @@ public:
|
||||
bool decodeAble() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H264_TYPE(*nal_ptr);
|
||||
//多slice情况下, first_mb_in_slice 表示其为一帧的开始
|
||||
// 多slice情况下, first_mb_in_slice 表示其为一帧的开始 [AUTO-TRANSLATED:80e88e88]
|
||||
// // 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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 264帧类
|
||||
* 264 frame class
|
||||
|
||||
* [AUTO-TRANSLATED:342ccb1e]
|
||||
*/
|
||||
using H264Frame = H264FrameHelper<FrameImp>;
|
||||
|
||||
/**
|
||||
* 防止内存拷贝的H264类
|
||||
* 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类
|
||||
* H264 class that prevents memory copying
|
||||
* Users can quickly wrap a pointer into a Frame class without copying using this type
|
||||
|
||||
* [AUTO-TRANSLATED:ff9be1c8]
|
||||
*/
|
||||
using H264FrameNoCacheAble = H264FrameHelper<FrameFromPtr>;
|
||||
|
||||
/**
|
||||
* 264视频通道
|
||||
* 264 video channel
|
||||
|
||||
* [AUTO-TRANSLATED:6936e76d]
|
||||
*/
|
||||
class H264Track : public VideoTrack {
|
||||
public:
|
||||
@ -94,6 +105,10 @@ public:
|
||||
/**
|
||||
* 不指定sps pps构造h264类型的媒体
|
||||
* 在随后的inputFrame中获取sps pps
|
||||
* Construct a media of h264 type without specifying sps pps
|
||||
* Get sps pps in the subsequent inputFrame
|
||||
|
||||
* [AUTO-TRANSLATED:84d01c7f]
|
||||
*/
|
||||
H264Track() = default;
|
||||
|
||||
@ -103,6 +118,14 @@ public:
|
||||
* @param pps pps帧数据
|
||||
* @param sps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param pps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* Construct a media of h264 type
|
||||
* @param sps sps frame data
|
||||
* @param pps pps frame data
|
||||
* @param sps_prefix_len 264 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param pps_prefix_len 264 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:702c1433]
|
||||
*/
|
||||
H264Track(const std::string &sps, const std::string &pps, int sps_prefix_len = 4, int pps_prefix_len = 4);
|
||||
|
||||
|
@ -62,7 +62,8 @@ void H264RtmpEncoder::flush() {
|
||||
bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
if (!_rtmp_packet) {
|
||||
_rtmp_packet = RtmpPacket::create();
|
||||
//flags/not config/cts预占位
|
||||
// flags/not config/cts预占位 [AUTO-TRANSLATED:7effb692]
|
||||
// flags/not config/cts placeholder
|
||||
_rtmp_packet->buffer.resize(5);
|
||||
}
|
||||
|
||||
@ -78,7 +79,8 @@ bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
_rtmp_packet->chunk_id = CHUNK_VIDEO;
|
||||
_rtmp_packet->stream_index = STREAM_MEDIA;
|
||||
_rtmp_packet->type_id = MSG_VIDEO;
|
||||
// 输出rtmp packet
|
||||
// 输出rtmp packet [AUTO-TRANSLATED:d72e89a7]
|
||||
// Output rtmp packet
|
||||
RtmpCodec::inputRtmp(_rtmp_packet);
|
||||
_rtmp_packet = nullptr;
|
||||
}, &_rtmp_packet->buffer);
|
||||
|
@ -19,6 +19,10 @@ namespace mediakit {
|
||||
/**
|
||||
* h264 Rtmp解码类
|
||||
* 将 h264 over rtmp 解复用出 h264-Frame
|
||||
* h264 Rtmp decoder class
|
||||
* Demultiplex h264-Frame from h264 over rtmp
|
||||
|
||||
* [AUTO-TRANSLATED:4908a1f3]
|
||||
*/
|
||||
class H264RtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@ -29,6 +33,10 @@ public:
|
||||
/**
|
||||
* 输入264 Rtmp包
|
||||
* @param rtmp Rtmp包
|
||||
* Input 264 Rtmp package
|
||||
* @param rtmp Rtmp package
|
||||
|
||||
* [AUTO-TRANSLATED:06f3e94c]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
|
||||
@ -39,6 +47,9 @@ private:
|
||||
|
||||
/**
|
||||
* 264 Rtmp打包类
|
||||
* 264 Rtmp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:e5bc7c66]
|
||||
*/
|
||||
class H264RtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@ -49,22 +60,39 @@ public:
|
||||
* 如果track不为空且包含sps pps信息,
|
||||
* 那么inputFrame时可以不输入sps pps
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case sps pps is input when inputFrame
|
||||
* If track is not empty and contains sps pps information,
|
||||
* then sps pps can be omitted when inputFrame
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:e61fdfed]
|
||||
*/
|
||||
H264RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入264帧,可以不带sps pps
|
||||
* @param frame 帧数据
|
||||
* Input 264 frame, sps pps can be omitted
|
||||
* @param frame Frame data
|
||||
|
||||
* [AUTO-TRANSLATED:caefd055]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache output
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config package
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
@ -51,7 +51,9 @@ bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||
}
|
||||
_last_seq = seq;
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始
|
||||
// 确保有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
|
||||
return _is_gop && !last_is_gop;
|
||||
}
|
||||
|
||||
@ -70,6 +72,23 @@ Table 1. Summary of NAL unit types and their payload structures
|
||||
28 FU-A Fragmentation unit 5.8
|
||||
29 FU-B Fragmentation unit 5.8
|
||||
30-31 undefined -
|
||||
/*
|
||||
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]
|
||||
*/
|
||||
|
||||
bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp){
|
||||
@ -82,7 +101,8 @@ bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
|
||||
}
|
||||
|
||||
bool H264RtpDecoder::unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp) {
|
||||
//STAP-A 单一时间的组合包
|
||||
// STAP-A 单一时间的组合包 [AUTO-TRANSLATED:cfa62307]
|
||||
// STAP-A single-time aggregation packet
|
||||
auto have_key_frame = false;
|
||||
auto end = ptr + size;
|
||||
while (ptr + 2 < end) {
|
||||
@ -105,7 +125,8 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
auto nal_suffix = *ptr & (~0x1F);
|
||||
FuFlags *fu = (FuFlags *) (ptr + 1);
|
||||
if (fu->start_bit) {
|
||||
//该帧的第一个rtp包
|
||||
// 该帧的第一个rtp包 [AUTO-TRANSLATED:a9581a23]
|
||||
// The first rtp packet of this frame
|
||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||
_frame->_buffer.push_back(nal_suffix | fu->nal_type);
|
||||
_frame->_pts = stamp;
|
||||
@ -113,28 +134,34 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
}
|
||||
|
||||
if (_fu_dropped) {
|
||||
//该帧不完整
|
||||
// 该帧不完整 [AUTO-TRANSLATED:6bd7eca7]
|
||||
// This frame is incomplete
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fu->start_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||
// 中间的或末尾的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
|
||||
_fu_dropped = true;
|
||||
_frame->_buffer.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
//后面追加数据
|
||||
// 后面追加数据 [AUTO-TRANSLATED:248516e9]
|
||||
// Append data
|
||||
_frame->_buffer.append((char *) ptr + 2, size - 2);
|
||||
|
||||
if (!fu->end_bit) {
|
||||
//非末尾包
|
||||
// 非末尾包 [AUTO-TRANSLATED:2e43ac3c]
|
||||
// Not the end packet
|
||||
return fu->start_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
|
||||
}
|
||||
|
||||
//确保下一次fu必须收到第一个包
|
||||
// 确保下一次fu必须收到第一个包 [AUTO-TRANSLATED:491d81ec]
|
||||
// Ensure that the next fu must receive the first packet
|
||||
_fu_dropped = true;
|
||||
//该帧最后一个rtp包,输出frame
|
||||
// 该帧最后一个rtp包,输出frame [AUTO-TRANSLATED:a648aaa5]
|
||||
// The last rtp packet of this frame, output frame
|
||||
outputFrame(rtp, _frame);
|
||||
return false;
|
||||
}
|
||||
@ -142,7 +169,8 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual payload
|
||||
return false;
|
||||
}
|
||||
auto frame = rtp->getPayload();
|
||||
@ -173,10 +201,12 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
|
||||
void H264RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame) {
|
||||
if (frame->dropAble()) {
|
||||
//不参与dts生成
|
||||
// 不参与dts生成 [AUTO-TRANSLATED:dff3b747]
|
||||
// Not involved in dts generation
|
||||
frame->_dts = frame->_pts;
|
||||
} else {
|
||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||
// rtsp没有dts,那么根据pts排序算法生成dts [AUTO-TRANSLATED:f37c17f3]
|
||||
// Rtsp does not have dts, so dts is generated according to the pts sorting algorithm
|
||||
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||
}
|
||||
|
||||
@ -196,17 +226,20 @@ void H264RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
if (!_sps || !_pps) {
|
||||
return;
|
||||
}
|
||||
//gop缓存从sps开始,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false
|
||||
// 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
|
||||
packRtp(_sps->data() + _sps->prefixSize(), _sps->size() - _sps->prefixSize(), pts, false, true);
|
||||
packRtp(_pps->data() + _pps->prefixSize(), _pps->size() - _pps->prefixSize(), pts, false, false);
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
if (len + 3 <= getRtpInfo().getMaxSize()) {
|
||||
// 采用STAP-A/Single NAL unit packet per H.264 模式
|
||||
// 采用STAP-A/Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:1a719984]
|
||||
// Use STAP-A/Single NAL unit packet per H.264 mode
|
||||
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
|
||||
} else {
|
||||
//STAP-A模式打包会大于MTU,所以采用FU-A模式
|
||||
// STAP-A模式打包会大于MTU,所以采用FU-A模式 [AUTO-TRANSLATED:f3923abc]
|
||||
// STAP-A mode packaging will be larger than MTU, so FU-A mode is used
|
||||
packRtpFu(ptr, len, pts, is_mark, gop_pos);
|
||||
}
|
||||
}
|
||||
@ -214,12 +247,14 @@ void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
|
||||
void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
auto packet_size = getRtpInfo().getMaxSize() - 2;
|
||||
if (len <= packet_size + 1) {
|
||||
// 小于FU-A打包最小字节长度要求,采用STAP-A/Single NAL unit packet per H.264 模式
|
||||
// 小于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
|
||||
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
//末尾5bit为nalu type,固定为28(FU-A)
|
||||
// 末尾5bit为nalu type,固定为28(FU-A) [AUTO-TRANSLATED:6293f1a9]
|
||||
// The last 5 bits are the nalu type, fixed to 28 (FU-A)
|
||||
auto fu_char_0 = (ptr[0] & (~0x1F)) | 28;
|
||||
auto fu_char_1 = H264_TYPE(ptr[0]);
|
||||
FuFlags *fu_flags = (FuFlags *) (&fu_char_1);
|
||||
@ -233,17 +268,23 @@ void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
|
||||
fu_flags->end_bit = 1;
|
||||
}
|
||||
|
||||
//传入nullptr先不做payload的内存拷贝
|
||||
// 传入nullptr先不做payload的内存拷贝 [AUTO-TRANSLATED:1858cf77]
|
||||
// Pass in nullptr first, do not copy the payload memory
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
|
||||
//rtp payload 负载部分
|
||||
// rtp payload 负载部分 [AUTO-TRANSLATED:aecf73cc]
|
||||
// rtp payload load part
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
//FU-A 第1个字节
|
||||
// FU-A 第1个字节 [AUTO-TRANSLATED:b5558495]
|
||||
// FU-A first byte
|
||||
payload[0] = fu_char_0;
|
||||
//FU-A 第2个字节
|
||||
// FU-A 第2个字节 [AUTO-TRANSLATED:6b4540bb]
|
||||
// FU-A second byte
|
||||
payload[1] = fu_char_1;
|
||||
//H264 数据
|
||||
// H264 数据 [AUTO-TRANSLATED:79204239]
|
||||
// H264 data
|
||||
memcpy(payload + 2, (uint8_t *) ptr + offset, packet_size);
|
||||
//输入到rtp环形缓存
|
||||
// 输入到rtp环形缓存 [AUTO-TRANSLATED:5208ef90]
|
||||
// Input to the rtp ring buffer
|
||||
RtpCodec::inputRtp(rtp, gop_pos);
|
||||
|
||||
offset += packet_size;
|
||||
@ -261,7 +302,8 @@ void H264RtpEncoder::packRtpSmallFrame(const char *data, size_t len, uint64_t pt
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
// 如果帧长度不超过mtu,为了兼容性 webrtc,采用STAP-A模式打包
|
||||
// 如果帧长度不超过mtu,为了兼容性 webrtc,采用STAP-A模式打包 [AUTO-TRANSLATED:a091199c]
|
||||
// If the frame length does not exceed mtu, for compatibility with webrtc, use STAP-A mode packaging
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, len + 3, is_mark, pts);
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
//STAP-A
|
||||
@ -274,7 +316,8 @@ void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, boo
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtpSingleNalu(const char *data, size_t len, uint64_t pts, bool is_mark, bool gop_pos) {
|
||||
// Single NAL unit packet per H.264 模式
|
||||
// Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:9332a8e4]
|
||||
// Single NAL unit packet per H.264 mode
|
||||
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, data, len, is_mark, pts), gop_pos);
|
||||
}
|
||||
|
||||
@ -300,7 +343,8 @@ bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
inputFrame_l(frame, true);
|
||||
} else {
|
||||
if (_last_frame) {
|
||||
//如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:19b68429]
|
||||
// If the timestamp changes, then the markbit is set to true
|
||||
inputFrame_l(_last_frame, _last_frame->pts() != frame->pts());
|
||||
}
|
||||
_last_frame = Frame::getCacheAbleFrame(frame);
|
||||
@ -310,7 +354,8 @@ bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
void H264RtpEncoder::flush() {
|
||||
if (_last_frame) {
|
||||
// 如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:6b1d0fe0]
|
||||
// If the timestamp changes, then the markbit is set to true
|
||||
inputFrame_l(_last_frame, true);
|
||||
_last_frame = nullptr;
|
||||
}
|
||||
@ -318,7 +363,8 @@ void H264RtpEncoder::flush() {
|
||||
|
||||
bool H264RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
|
||||
if (frame->keyFrame()) {
|
||||
//保证每一个关键帧前都有SPS与PPS
|
||||
// 保证每一个关键帧前都有SPS与PPS [AUTO-TRANSLATED:9d1a9d5e]
|
||||
// Ensure that there are SPS and PPS before each key frame
|
||||
insertConfigFrame(frame->pts());
|
||||
}
|
||||
packRtp(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), frame->pts(), is_mark, false);
|
||||
|
@ -22,6 +22,11 @@ namespace mediakit {
|
||||
* h264 rtp解码类
|
||||
* 将 h264 over rtsp-rtp 解复用出 h264-Frame
|
||||
* rfc3984
|
||||
* h264 rtp decoder class
|
||||
* Demultiplex h264-Frame from h264 over rtsp-rtp
|
||||
* rfc3984
|
||||
|
||||
* [AUTO-TRANSLATED:84b4831b]
|
||||
*/
|
||||
class H264RtpDecoder : public RtpCodec{
|
||||
public:
|
||||
@ -33,6 +38,11 @@ public:
|
||||
* 输入264 rtp包
|
||||
* @param rtp rtp包
|
||||
* @param key_pos 此参数忽略之
|
||||
* Input 264 rtp packet
|
||||
* @param rtp rtp packet
|
||||
* @param key_pos This parameter is ignored
|
||||
|
||||
* [AUTO-TRANSLATED:a9ed29db]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
|
||||
|
||||
@ -56,6 +66,9 @@ private:
|
||||
|
||||
/**
|
||||
* 264 rtp打包类
|
||||
* 264 rtp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:baed5b50]
|
||||
*/
|
||||
class H264RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@ -64,11 +77,19 @@ public:
|
||||
/**
|
||||
* 输入264帧
|
||||
* @param frame 帧数据,必须
|
||||
* Input 264 frame
|
||||
* @param frame Frame data, required
|
||||
|
||||
* [AUTO-TRANSLATED:1190bc60]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame buffers in the output
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
@ -87,6 +108,6 @@ private:
|
||||
Frame::Ptr _last_frame;
|
||||
};
|
||||
|
||||
}//namespace mediakit{
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_H264RTPCODEC_H
|
||||
|
@ -219,6 +219,9 @@ void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
|
||||
|
||||
/**
|
||||
* h265类型sdp
|
||||
* h265 type sdp
|
||||
|
||||
* [AUTO-TRANSLATED:4418a7df]
|
||||
*/
|
||||
class H265Sdp : public Sdp {
|
||||
public:
|
||||
@ -228,9 +231,17 @@ public:
|
||||
* @param pps 265 pps,不带0x00000001头
|
||||
* @param payload_type rtp payload type 默认96
|
||||
* @param bitrate 比特率
|
||||
* Constructor
|
||||
* @param sps 265 sps, without 0x00000001 header
|
||||
* @param pps 265 pps, without 0x00000001 header
|
||||
* @param payload_type rtp payload type, default 96
|
||||
* @param bitrate Bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:93f4ec48]
|
||||
*/
|
||||
H265Sdp(const string &strVPS, const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
|
||||
//视频通道
|
||||
// 视频通道 [AUTO-TRANSLATED:642ca881]
|
||||
// Video channel
|
||||
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
||||
if (bitrate) {
|
||||
_printer << "b=AS:" << bitrate << "\r\n";
|
||||
@ -276,7 +287,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
auto sps = decodeBase64(map["sprop-sps"]);
|
||||
auto pps = decodeBase64(map["sprop-pps"]);
|
||||
if (sps.empty() || pps.empty()) {
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps [AUTO-TRANSLATED:9300510b]
|
||||
// If there is no sps/pps in the sdp, then it may be possible to recover sps/pps from the subsequent rtp
|
||||
return std::make_shared<H265Track>();
|
||||
}
|
||||
return std::make_shared<H265Track>(vps, sps, pps, 0, 0, 0);
|
||||
|
@ -65,7 +65,8 @@ public:
|
||||
bool keyFrame() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H265_TYPE(*nal_ptr);
|
||||
// 参考自FFmpeg: IRAP VCL NAL unit types span the range
|
||||
// 参考自FFmpeg: IRAP VCL NAL unit types span the range [AUTO-TRANSLATED:45413c06]
|
||||
// Referenced from FFmpeg: IRAP VCL NAL unit types span the range
|
||||
// [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].
|
||||
return (type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23) && decodeAble() ;
|
||||
}
|
||||
@ -93,24 +94,35 @@ public:
|
||||
bool decodeAble() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H265_TYPE(*nal_ptr);
|
||||
//多slice情况下, first_slice_segment_in_pic_flag 表示其为一帧的开始
|
||||
// 多slice情况下, first_slice_segment_in_pic_flag 表示其为一帧的开始 [AUTO-TRANSLATED:0427551b]
|
||||
// In the case of multiple slices, first_slice_segment_in_pic_flag indicates the beginning of a frame
|
||||
return type >= NAL_TRAIL_N && type <= NAL_RSV_IRAP_VCL23 && (nal_ptr[2] & 0x80);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 265帧类
|
||||
* 265 frame class
|
||||
|
||||
* [AUTO-TRANSLATED:9141a4be]
|
||||
*/
|
||||
using H265Frame = H265FrameHelper<FrameImp>;
|
||||
|
||||
/**
|
||||
* 防止内存拷贝的H265类
|
||||
* 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类
|
||||
* H265 class to prevent memory copying
|
||||
* Users can quickly wrap a pointer into a Frame class without copying through this type
|
||||
|
||||
* [AUTO-TRANSLATED:44bde991]
|
||||
*/
|
||||
using H265FrameNoCacheAble = H265FrameHelper<FrameFromPtr>;
|
||||
|
||||
/**
|
||||
* 265视频通道
|
||||
* 265 video channel
|
||||
|
||||
* [AUTO-TRANSLATED:27c65a36]
|
||||
*/
|
||||
class H265Track : public VideoTrack {
|
||||
public:
|
||||
@ -119,6 +131,10 @@ public:
|
||||
/**
|
||||
* 不指定sps pps构造h265类型的媒体
|
||||
* 在随后的inputFrame中获取sps pps
|
||||
* Construct a h265 media without specifying sps pps
|
||||
* Get sps pps in the subsequent inputFrame
|
||||
|
||||
* [AUTO-TRANSLATED:bf86e048]
|
||||
*/
|
||||
H265Track() = default;
|
||||
|
||||
@ -130,6 +146,16 @@ public:
|
||||
* @param vps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* Construct a h265 media
|
||||
* @param vps vps frame data
|
||||
* @param sps sps frame data
|
||||
* @param pps pps frame data
|
||||
* @param vps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param sps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param pps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:a8c42d9f]
|
||||
*/
|
||||
H265Track(const std::string &vps,const std::string &sps, const std::string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4);
|
||||
|
||||
|
@ -22,12 +22,14 @@ namespace mediakit {
|
||||
|
||||
void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
if (_info.codec == CodecInvalid) {
|
||||
// 先判断是否为增强型rtmp
|
||||
// 先判断是否为增强型rtmp [AUTO-TRANSLATED:86c4f86a]
|
||||
// First, determine if it is an enhanced rtmp
|
||||
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
|
||||
}
|
||||
|
||||
if (_info.is_enhanced) {
|
||||
// 增强型rtmp
|
||||
// 增强型rtmp [AUTO-TRANSLATED:d7d72114]
|
||||
// Enhanced rtmp
|
||||
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
|
||||
if (!_info.is_enhanced || _info.codec != CodecH265) {
|
||||
throw std::invalid_argument("Invalid enhanced-rtmp hevc packet!");
|
||||
@ -61,7 +63,8 @@ void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 国内扩展(12) H265 rtmp
|
||||
// 国内扩展(12) H265 rtmp [AUTO-TRANSLATED:ba272139]
|
||||
// Domestic extension (12) H265 rtmp
|
||||
if (pkt->isConfigFrame()) {
|
||||
CHECK_RET(pkt->size() > 5);
|
||||
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
|
||||
@ -133,7 +136,8 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
_rtmp_packet->chunk_id = CHUNK_VIDEO;
|
||||
_rtmp_packet->stream_index = STREAM_MEDIA;
|
||||
_rtmp_packet->type_id = MSG_VIDEO;
|
||||
// 输出rtmp packet
|
||||
// 输出rtmp packet [AUTO-TRANSLATED:d72e89a7]
|
||||
// Output rtmp packet
|
||||
RtmpCodec::inputRtmp(_rtmp_packet);
|
||||
_rtmp_packet = nullptr;
|
||||
}, &_rtmp_packet->buffer);
|
||||
|
@ -19,6 +19,10 @@ namespace mediakit {
|
||||
/**
|
||||
* h265 Rtmp解码类
|
||||
* 将 h265 over rtmp 解复用出 h265-Frame
|
||||
* h265 Rtmp decoder class
|
||||
* Demultiplex h265-Frame from h265 over rtmp
|
||||
|
||||
* [AUTO-TRANSLATED:2768e4bd]
|
||||
*/
|
||||
class H265RtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@ -29,6 +33,10 @@ public:
|
||||
/**
|
||||
* 输入265 Rtmp包
|
||||
* @param rtmp Rtmp包
|
||||
* Input 265 Rtmp packet
|
||||
* @param rtmp Rtmp packet
|
||||
|
||||
* [AUTO-TRANSLATED:63dbe33f]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
|
||||
@ -42,6 +50,9 @@ protected:
|
||||
|
||||
/**
|
||||
* 265 Rtmp打包类
|
||||
* 265 Rtmp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:5891c800]
|
||||
*/
|
||||
class H265RtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@ -52,22 +63,39 @@ public:
|
||||
* 如果track不为空且包含sps pps信息,
|
||||
* 那么inputFrame时可以不输入sps pps
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case sps pps is input when inputFrame
|
||||
* If track is not empty and contains sps pps information,
|
||||
* Then sps pps can be omitted when inputFrame
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:e61fdfed]
|
||||
*/
|
||||
H265RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入265帧,可以不带sps pps
|
||||
* @param frame 帧数据
|
||||
* Input 265 frame, sps pps can be omitted
|
||||
* @param frame Frame data
|
||||
|
||||
* [AUTO-TRANSLATED:7d1be1e7]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache output
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config packet
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
namespace mediakit{
|
||||
|
||||
//https://datatracker.ietf.org/doc/rfc7798/
|
||||
//H265 nalu 头两个字节的定义
|
||||
// H265 nalu 头两个字节的定义 [AUTO-TRANSLATED:d896dd59]
|
||||
// H265 nalu header definition of the first two bytes
|
||||
/*
|
||||
0 1
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
@ -71,7 +72,8 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
||||
*/
|
||||
bool H265RtpDecoder::unpackAp(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp){
|
||||
bool have_key_frame = false;
|
||||
//忽略PayloadHdr
|
||||
// 忽略PayloadHdr [AUTO-TRANSLATED:9868ddb5]
|
||||
// Ignore PayloadHdr
|
||||
CHECK_SIZE(size, 2, have_key_frame);
|
||||
ptr += 2;
|
||||
size -= 2;
|
||||
@ -125,7 +127,8 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
auto e_bit = (ptr[2] >> 6) & 0x01;
|
||||
auto type = ptr[2] & 0x3f;
|
||||
if (s_bit) {
|
||||
//该帧的第一个rtp包
|
||||
// 该帧的第一个rtp包 [AUTO-TRANSLATED:a9581a23]
|
||||
// The first rtp packet of this frame
|
||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||
_frame->_buffer.push_back((type << 1) | (ptr[0] & 0x81));
|
||||
_frame->_buffer.push_back(ptr[1]);
|
||||
@ -134,22 +137,26 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
}
|
||||
|
||||
if (_fu_dropped) {
|
||||
//该帧不完整
|
||||
// 该帧不完整 [AUTO-TRANSLATED:6bd7eca7]
|
||||
// This frame is incomplete
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!s_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||
// 中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃 [AUTO-TRANSLATED:6953b332]
|
||||
// The middle or end rtp packet, its seq must be continuous, otherwise it means rtp packet loss, then this frame is incomplete and must be discarded
|
||||
_fu_dropped = true;
|
||||
_frame->_buffer.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
//跳过PayloadHdr + FU header
|
||||
// 跳过PayloadHdr + FU header [AUTO-TRANSLATED:51ec6760]
|
||||
// Skip PayloadHdr + FU header
|
||||
ptr += 3;
|
||||
size -= 3;
|
||||
if (_using_donl_field) {
|
||||
//DONL确保不少于2个字节
|
||||
// DONL确保不少于2个字节 [AUTO-TRANSLATED:7e72ecc1]
|
||||
// DONL must be no less than 2 bytes
|
||||
CHECK_SIZE(size, 2, false);
|
||||
uint16_t donl = AV_RB16(ptr);
|
||||
size -= 2;
|
||||
@ -158,17 +165,21 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
|
||||
CHECK_SIZE(size, 1, false);
|
||||
|
||||
//后面追加数据
|
||||
// 后面追加数据 [AUTO-TRANSLATED:248516e9]
|
||||
// Append data later
|
||||
_frame->_buffer.append((char *) ptr, size);
|
||||
|
||||
if (!e_bit) {
|
||||
//非末尾包
|
||||
// 非末尾包 [AUTO-TRANSLATED:2e43ac3c]
|
||||
// Non-end packet
|
||||
return s_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
|
||||
}
|
||||
|
||||
//确保下一次fu必须收到第一个包
|
||||
// 确保下一次fu必须收到第一个包 [AUTO-TRANSLATED:491d81ec]
|
||||
// Ensure that the next fu must receive the first packet
|
||||
_fu_dropped = true;
|
||||
//该帧最后一个rtp包
|
||||
// 该帧最后一个rtp包 [AUTO-TRANSLATED:ea395f0e]
|
||||
// The last rtp packet of this frame
|
||||
outputFrame(rtp, _frame);
|
||||
return false;
|
||||
}
|
||||
@ -182,14 +193,16 @@ bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||
}
|
||||
_last_seq = seq;
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始 [AUTO-TRANSLATED:115ae07c]
|
||||
// Ensure that when there is sps rtp, gop starts from sps; otherwise, it starts from the key frame
|
||||
return _is_gop && !last_is_gop;
|
||||
}
|
||||
|
||||
bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual payload
|
||||
return false;
|
||||
}
|
||||
auto frame = rtp->getPayload();
|
||||
@ -229,10 +242,12 @@ bool H265RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
|
||||
|
||||
void H265RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame) {
|
||||
if (frame->dropAble()) {
|
||||
//不参与dts生成
|
||||
// 不参与dts生成 [AUTO-TRANSLATED:dff3b747]
|
||||
// Not involved in dts generation
|
||||
frame->_dts = frame->_pts;
|
||||
} else {
|
||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||
// rtsp没有dts,那么根据pts排序算法生成dts [AUTO-TRANSLATED:f37c17f3]
|
||||
// rtsp does not have dts, so dts is generated according to the pts sorting algorithm
|
||||
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||
}
|
||||
|
||||
@ -270,19 +285,26 @@ void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
|
||||
}
|
||||
|
||||
{
|
||||
// 传入nullptr先不做payload的内存拷贝
|
||||
// 传入nullptr先不做payload的内存拷贝 [AUTO-TRANSLATED:7ed49f0a]
|
||||
// Pass in nullptr first, do not copy the payload memory
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, max_size + 3, mark_bit, pts);
|
||||
// rtp payload 负载部分
|
||||
// rtp payload 负载部分 [AUTO-TRANSLATED:03a5ef9b]
|
||||
// rtp payload load part
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
// FU 第1个字节,表明为FU
|
||||
// FU 第1个字节,表明为FU [AUTO-TRANSLATED:9cf07fda]
|
||||
// FU first byte, indicating FU
|
||||
payload[0] = 49 << 1;
|
||||
// FU 第2个字节貌似固定为1
|
||||
// FU 第2个字节貌似固定为1 [AUTO-TRANSLATED:77983091]
|
||||
// FU second byte seems to be fixed to 1
|
||||
payload[1] = ptr[1]; // 1;
|
||||
// FU 第3个字节
|
||||
// FU 第3个字节 [AUTO-TRANSLATED:c627abd0]
|
||||
// FU third byte
|
||||
payload[2] = s_e_flags;
|
||||
// H265 数据
|
||||
// H265 数据 [AUTO-TRANSLATED:a2c3135f]
|
||||
// H265 data
|
||||
memcpy(payload + 3, ptr + offset, max_size);
|
||||
// 输入到rtp环形缓存
|
||||
// 输入到rtp环形缓存 [AUTO-TRANSLATED:6bafd42b]
|
||||
// Input to rtp ring buffer
|
||||
RtpCodec::inputRtp(rtp, fu_start && gop_pos);
|
||||
}
|
||||
|
||||
@ -296,7 +318,8 @@ void H265RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
|
||||
//signal-nalu
|
||||
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, ptr, len, is_mark, pts), gop_pos);
|
||||
} else {
|
||||
//FU-A模式
|
||||
// FU-A模式 [AUTO-TRANSLATED:a273a49c]
|
||||
// FU-A mode
|
||||
packRtpFu(ptr, len, pts, is_mark, gop_pos);
|
||||
}
|
||||
}
|
||||
@ -305,7 +328,8 @@ void H265RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
WarnL<<" not ok";
|
||||
return;
|
||||
}
|
||||
//gop缓存从vps 开始,vps ,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false
|
||||
// gop缓存从vps 开始,vps ,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false [AUTO-TRANSLATED:2534b06f]
|
||||
// gop cache starts from vps, vps, sps, pps followed by key frames with the same timestamp, so mark bit is false
|
||||
packRtp(_vps->data() + _vps->prefixSize(), _vps->size() - _vps->prefixSize(), pts, false, true);
|
||||
packRtp(_sps->data() + _sps->prefixSize(), _sps->size() - _sps->prefixSize(), pts, false, false);
|
||||
packRtp(_pps->data() + _pps->prefixSize(), _pps->size() - _pps->prefixSize(), pts, false, false);
|
||||
@ -313,7 +337,8 @@ void H265RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
}
|
||||
bool H265RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
|
||||
if (frame->keyFrame()) {
|
||||
//保证每一个关键帧前都有SPS PPS VPS
|
||||
// 保证每一个关键帧前都有SPS PPS VPS [AUTO-TRANSLATED:9189f8d7]
|
||||
// Ensure that there are SPS PPS VPS before each key frame
|
||||
insertConfigFrame(frame->pts());
|
||||
}
|
||||
packRtp(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), frame->pts(), is_mark, false);
|
||||
@ -347,7 +372,8 @@ bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
inputFrame_l(frame, true);
|
||||
} else {
|
||||
if (_last_frame) {
|
||||
//如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:19b68429]
|
||||
// If the timestamp changes, then markbit is set to true
|
||||
inputFrame_l(_last_frame, _last_frame->pts() != frame->pts());
|
||||
}
|
||||
_last_frame = Frame::getCacheAbleFrame(frame);
|
||||
@ -357,7 +383,8 @@ bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
void H265RtpEncoder::flush() {
|
||||
if (_last_frame) {
|
||||
// 如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:6b1d0fe0]
|
||||
// If the timestamp changes, then markbit is set to true
|
||||
inputFrame_l(_last_frame, true);
|
||||
_last_frame = nullptr;
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ namespace mediakit {
|
||||
* h265 rtp解码类
|
||||
* 将 h265 over rtsp-rtp 解复用出 h265-Frame
|
||||
* 《草案(H265-over-RTP)draft-ietf-payload-rtp-h265-07.pdf》
|
||||
* h265 rtp decoder class
|
||||
* Demultiplex h265-Frame from h265 over rtsp-rtp
|
||||
* 《Draft (H265-over-RTP) draft-ietf-payload-rtp-h265-07.pdf》
|
||||
|
||||
* [AUTO-TRANSLATED:24e7e278]
|
||||
*/
|
||||
class H265RtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@ -33,6 +38,11 @@ public:
|
||||
* 输入265 rtp包
|
||||
* @param rtp rtp包
|
||||
* @param key_pos 此参数忽略之
|
||||
* Input 265 rtp packet
|
||||
* @param rtp rtp packet
|
||||
* @param key_pos This parameter is ignored
|
||||
|
||||
* [AUTO-TRANSLATED:35e8fa1d]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
|
||||
|
||||
@ -57,6 +67,9 @@ private:
|
||||
|
||||
/**
|
||||
* 265 rtp打包类
|
||||
* 265 rtp packer class
|
||||
|
||||
* [AUTO-TRANSLATED:4b3f96fe]
|
||||
*/
|
||||
class H265RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@ -65,11 +78,19 @@ public:
|
||||
/**
|
||||
* 输入265帧
|
||||
* @param frame 帧数据,必须
|
||||
* Input 265 frame
|
||||
* @param frame Frame data, required
|
||||
|
||||
* [AUTO-TRANSLATED:48454707]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache in output
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
@ -85,6 +106,6 @@ private:
|
||||
Frame::Ptr _last_frame;
|
||||
};
|
||||
|
||||
}//namespace mediakit{
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_H265RTPCODEC_H
|
||||
|
@ -42,11 +42,16 @@ public:
|
||||
/**
|
||||
* JPEG/MJPEG帧
|
||||
* @param pix_type pixel format type; AV_PIX_FMT_YUVJ422P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV422P) : 1; AV_PIX_FMT_YUVJ420P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV420P) : 0
|
||||
* JPEG/MJPEG frame
|
||||
* @param pix_type pixel format type; AV_PIX_FMT_YUVJ422P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV422P) : 1; AV_PIX_FMT_YUVJ420P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV420P) : 0
|
||||
|
||||
* [AUTO-TRANSLATED:d746e541]
|
||||
*/
|
||||
template <typename... ARGS>
|
||||
JPEGFrame(uint8_t pix_type, ARGS &&...args) : Parent(std::forward<ARGS>(args)...) {
|
||||
_pix_type = pix_type;
|
||||
// JFIF头固定20个字节长度
|
||||
// JFIF头固定20个字节长度 [AUTO-TRANSLATED:bd63b447]
|
||||
// JFIF header is fixed at 20 bytes in length
|
||||
CHECK(this->size() > kJFIFSize);
|
||||
}
|
||||
size_t prefixSize() const override { return 0; }
|
||||
|
@ -632,7 +632,8 @@ void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uin
|
||||
for (j = 0; j < tables; j++)
|
||||
qtables[nb_qtables + j] = buf + i + 5 + j * 65;
|
||||
nb_qtables += tables;
|
||||
// 大致忽略DQT/qtable所占字节数,提高搜寻速度
|
||||
// 大致忽略DQT/qtable所占字节数,提高搜寻速度 [AUTO-TRANSLATED:63423997]
|
||||
// Roughly ignore the number of bytes occupied by DQT/qtable to improve search speed
|
||||
i += tables << 6;
|
||||
} else if (buf[i + 1] == SOF0) {
|
||||
if (buf[i + 14] != 17 || buf[i + 17] != 17) {
|
||||
@ -642,7 +643,8 @@ void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uin
|
||||
}
|
||||
h = (buf[i + 5] * 256 + buf[i + 6]) / 8;
|
||||
w = (buf[i + 7] * 256 + buf[i + 8]) / 8;
|
||||
// 大致忽略SOF0所占字节数,提高搜寻速度
|
||||
// 大致忽略SOF0所占字节数,提高搜寻速度 [AUTO-TRANSLATED:438cbf70]
|
||||
// Roughly ignore the number of bytes occupied by SOF0 to improve search speed
|
||||
i += 16;
|
||||
} else if (buf[i + 1] == DHT) {
|
||||
int dht_size = AV_RB16(&buf[i + 2]);
|
||||
@ -811,7 +813,8 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
auto seq = rtp->getSeq();
|
||||
auto marker = rtp->getHeader()->mark;
|
||||
if (size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual load
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -829,7 +832,8 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JPEGRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
// JFIF头固定20个字节长度
|
||||
// JFIF头固定20个字节长度 [AUTO-TRANSLATED:bd63b447]
|
||||
// JFIF header is fixed at 20 bytes in length
|
||||
auto ptr = (uint8_t *)frame->data() + frame->prefixSize() + JPEGFrameImp::kJFIFSize;
|
||||
auto len = frame->size() - frame->prefixSize() - JPEGFrameImp::kJFIFSize;
|
||||
auto pts = frame->pts();
|
||||
|
@ -19,6 +19,9 @@ struct PayloadContext {
|
||||
|
||||
/**
|
||||
* 通用 rtp解码类
|
||||
* General rtp decoding class
|
||||
|
||||
* [AUTO-TRANSLATED:41b57089]
|
||||
*/
|
||||
class JPEGRtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@ -30,6 +33,12 @@ public:
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
* Input rtp and decode
|
||||
* @param rtp rtp data packet
|
||||
* @param key_pos This parameter is internally forced to false, please ignore it
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:2993fcbe]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
|
@ -20,6 +20,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* L16类型SDP
|
||||
* L16 type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:11b1196d]
|
||||
*/
|
||||
class L16Sdp : public Sdp {
|
||||
public:
|
||||
@ -29,6 +32,14 @@ public:
|
||||
* @param channels 通道数
|
||||
* @param sample_rate 音频采样率
|
||||
* @param bitrate 比特率
|
||||
* L16 sampling bit width is fixed to 16 bits
|
||||
* @param payload_type rtp payload type
|
||||
* @param channels number of channels
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param bitrate bitrate
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7a08a400]
|
||||
*/
|
||||
L16Sdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
|
||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||
|
@ -18,6 +18,10 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* L16音频通道
|
||||
* L16 audio channel
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7a4b086f]
|
||||
*/
|
||||
class L16Track : public AudioTrackImp{
|
||||
public:
|
||||
|
@ -20,6 +20,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* Opus类型SDP
|
||||
* Opus type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:6c0a72ed]
|
||||
*/
|
||||
class OpusSdp : public Sdp {
|
||||
public:
|
||||
@ -29,6 +32,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* Construct opus sdp
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sample rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:40713e9d]
|
||||
*/
|
||||
OpusSdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
|
||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||
|
@ -18,6 +18,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* Opus帧音频通道
|
||||
* Opus frame audio channel
|
||||
|
||||
* [AUTO-TRANSLATED:522e95da]
|
||||
*/
|
||||
class OpusTrack : public AudioTrackImp{
|
||||
public:
|
||||
@ -25,11 +28,13 @@ public:
|
||||
OpusTrack() : AudioTrackImp(CodecOpus,48000,2,16){}
|
||||
|
||||
private:
|
||||
//克隆该Track
|
||||
// 克隆该Track [AUTO-TRANSLATED:9a15682a]
|
||||
// Clone this Track
|
||||
Track::Ptr clone() const override {
|
||||
return std::make_shared<OpusTrack>(*this);
|
||||
}
|
||||
//生成sdp
|
||||
// 生成sdp [AUTO-TRANSLATED:663a9367]
|
||||
// Generate sdp
|
||||
Sdp::Ptr getSdp(uint8_t payload_type) const override ;
|
||||
};
|
||||
|
||||
|
@ -2155,7 +2155,8 @@ exit:
|
||||
|
||||
void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight)
|
||||
{
|
||||
// ¿í¸ß¼ÆË㹫ʽ
|
||||
// ¿í¸ß¼ÆË㹫ʽ [AUTO-TRANSLATED:e2d61727]
|
||||
// What is the frame rate
|
||||
int iCodeWidth = 0;
|
||||
int iCodedHeight = 0;
|
||||
iCodeWidth = 16 * ptSps->iMbWidth;
|
||||
@ -2278,7 +2279,8 @@ void h265GeFramerate(T_HEVCVPS *ptVps, T_HEVCSPS *ptSps,float *pfFramerate)
|
||||
*pfFramerate = (float)(ptSps->tVui.u32VuiTimeScale) / (float)(ptSps->tVui.u32VuiNumUnitsInTick);
|
||||
}
|
||||
else{
|
||||
//vps sps可能不包含帧率
|
||||
// vps sps可能不包含帧率 [AUTO-TRANSLATED:15424320]
|
||||
// vps sps may not contain frame rate
|
||||
*pfFramerate = 0.0F;
|
||||
RPT(RPT_WRN, "frame rate:0");
|
||||
}
|
||||
|
@ -144,6 +144,11 @@ typedef struct T_AVRational{
|
||||
/***
|
||||
* Sequence parameter set
|
||||
* ¿É²Î¿¼H264±ê×¼µÚ7½ÚºÍ¸½Â¼D E
|
||||
/***
|
||||
* Sequence parameter set
|
||||
* H.264 sequence parameter set, version 7 and above, D E
|
||||
|
||||
* [AUTO-TRANSLATED:bd590cb8]
|
||||
*/
|
||||
#define Extended_SAR 255
|
||||
|
||||
@ -490,7 +495,8 @@ typedef struct {
|
||||
int log2_sao_offset_scale_luma;
|
||||
int log2_sao_offset_scale_chroma;
|
||||
|
||||
// 可以根据需要添加更多字段
|
||||
// 可以根据需要添加更多字段 [AUTO-TRANSLATED:57b9a7c1]
|
||||
// You can add more fields as needed
|
||||
} T_HEVC_PPS;
|
||||
|
||||
typedef struct T_GetBitContext{
|
||||
|
@ -35,9 +35,11 @@ onceToken token([]() {
|
||||
#else
|
||||
string ffmpeg_bin = trim(System::execute("which ffmpeg"));
|
||||
#endif
|
||||
//默认ffmpeg命令路径为环境变量中路径
|
||||
// 默认ffmpeg命令路径为环境变量中路径 [AUTO-TRANSLATED:40c35597]
|
||||
// Default ffmpeg command path is the path in the environment variable
|
||||
mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin;
|
||||
//ffmpeg日志保存路径
|
||||
// ffmpeg日志保存路径 [AUTO-TRANSLATED:e455732d]
|
||||
// ffmpeg log save path
|
||||
mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log";
|
||||
mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s";
|
||||
mINI::Instance()[kSnap] = "%s -i %s -y -f mjpeg -frames:v 1 -an %s";
|
||||
@ -104,7 +106,8 @@ void FFmpegSource::play(const string &ffmpeg_cmd_key, const string &src_url, con
|
||||
InfoL << cmd;
|
||||
|
||||
if (is_local_ip(_media_info.host)) {
|
||||
// 推流给自己的,通过判断流是否注册上来判断是否正常
|
||||
// 推流给自己的,通过判断流是否注册上来判断是否正常 [AUTO-TRANSLATED:423f2be6]
|
||||
// Push stream to yourself, judge whether the stream is registered to determine whether it is normal
|
||||
if (_media_info.schema != RTSP_SCHEMA && _media_info.schema != RTMP_SCHEMA) {
|
||||
cb(SockException(Err_other, "本服务只支持rtmp/rtsp推流"));
|
||||
return;
|
||||
@ -113,41 +116,50 @@ void FFmpegSource::play(const string &ffmpeg_cmd_key, const string &src_url, con
|
||||
findAsync(timeout_ms, [cb, weakSelf, timeout_ms](const MediaSource::Ptr &src) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
// 自己已经销毁
|
||||
// 自己已经销毁 [AUTO-TRANSLATED:3d45c3b0]
|
||||
// Self has been destroyed
|
||||
return;
|
||||
}
|
||||
if (src) {
|
||||
// 推流给自己成功
|
||||
// 推流给自己成功 [AUTO-TRANSLATED:65dba71b]
|
||||
// Push stream to yourself successfully
|
||||
cb(SockException());
|
||||
strongSelf->onGetMediaSource(src);
|
||||
strongSelf->startTimer(timeout_ms);
|
||||
return;
|
||||
}
|
||||
//推流失败
|
||||
// 推流失败 [AUTO-TRANSLATED:4d8d226a]
|
||||
// Push stream failed
|
||||
if (!strongSelf->_process.wait(false)) {
|
||||
// ffmpeg进程已经退出
|
||||
// ffmpeg进程已经退出 [AUTO-TRANSLATED:04193893]
|
||||
// ffmpeg process has exited
|
||||
cb(SockException(Err_other, StrPrinter << "ffmpeg已经退出,exit code = " << strongSelf->_process.exit_code()));
|
||||
return;
|
||||
}
|
||||
// ffmpeg进程还在线,但是等待推流超时
|
||||
// ffmpeg进程还在线,但是等待推流超时 [AUTO-TRANSLATED:9f71f17b]
|
||||
// ffmpeg process is still online, but waiting for the stream to timeout
|
||||
cb(SockException(Err_other, "等待超时"));
|
||||
});
|
||||
} else{
|
||||
//推流给其他服务器的,通过判断FFmpeg进程是否在线判断是否成功
|
||||
// 推流给其他服务器的,通过判断FFmpeg进程是否在线判断是否成功 [AUTO-TRANSLATED:9b963da5]
|
||||
// Push stream to other servers, judge whether it is successful by judging whether the FFmpeg process is online
|
||||
weak_ptr<FFmpegSource> weakSelf = shared_from_this();
|
||||
_timer = std::make_shared<Timer>(timeout_ms / 1000.0f, [weakSelf, cb, timeout_ms]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
// 自身已经销毁
|
||||
// 自身已经销毁 [AUTO-TRANSLATED:5f954f8a]
|
||||
// Self has been destroyed
|
||||
return false;
|
||||
}
|
||||
// FFmpeg还在线,那么我们认为推流成功
|
||||
// FFmpeg还在线,那么我们认为推流成功 [AUTO-TRANSLATED:4330df49]
|
||||
// FFmpeg is still online, so we think the push stream is successful
|
||||
if (strongSelf->_process.wait(false)) {
|
||||
cb(SockException());
|
||||
strongSelf->startTimer(timeout_ms);
|
||||
return false;
|
||||
}
|
||||
// ffmpeg进程已经退出
|
||||
// ffmpeg进程已经退出 [AUTO-TRANSLATED:04193893]
|
||||
// ffmpeg process has exited
|
||||
cb(SockException(Err_other, StrPrinter << "ffmpeg已经退出,exit code = " << strongSelf->_process.exit_code()));
|
||||
return false;
|
||||
}, _poller);
|
||||
@ -162,9 +174,11 @@ void FFmpegSource::findAsync(int maxWaitMS, const function<void(const MediaSourc
|
||||
}
|
||||
|
||||
void *listener_tag = this;
|
||||
// 若干秒后执行等待媒体注册超时回调
|
||||
// 若干秒后执行等待媒体注册超时回调 [AUTO-TRANSLATED:71010a04]
|
||||
// Execute the media registration timeout callback after a few seconds
|
||||
auto onRegistTimeout = _poller->doDelayTask(maxWaitMS, [cb, listener_tag]() {
|
||||
// 取消监听该事件
|
||||
// 取消监听该事件 [AUTO-TRANSLATED:31297323]
|
||||
// Cancel listening to this event
|
||||
NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
|
||||
cb(nullptr);
|
||||
return 0;
|
||||
@ -174,7 +188,8 @@ void FFmpegSource::findAsync(int maxWaitMS, const function<void(const MediaSourc
|
||||
auto onRegist = [listener_tag, weakSelf, cb, onRegistTimeout](BroadcastMediaChangedArgs) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
// 本身已经销毁,取消延时任务
|
||||
// 本身已经销毁,取消延时任务 [AUTO-TRANSLATED:cc2e420f]
|
||||
// Self has been destroyed, cancel the delayed task
|
||||
onRegistTimeout->cancel();
|
||||
NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
|
||||
return;
|
||||
@ -182,29 +197,38 @@ void FFmpegSource::findAsync(int maxWaitMS, const function<void(const MediaSourc
|
||||
|
||||
if (!bRegist || sender.getSchema() != strongSelf->_media_info.schema ||
|
||||
!equalMediaTuple(sender.getMediaTuple(), strongSelf->_media_info)) {
|
||||
// 不是自己感兴趣的事件,忽略之
|
||||
// 不是自己感兴趣的事件,忽略之 [AUTO-TRANSLATED:f61f5668]
|
||||
// Not an event of interest, ignore it
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找的流终于注册上了;取消延时任务,防止多次回调
|
||||
// 查找的流终于注册上了;取消延时任务,防止多次回调 [AUTO-TRANSLATED:66fc5abf]
|
||||
// The stream you are looking for is finally registered; cancel the delayed task to prevent multiple callbacks
|
||||
onRegistTimeout->cancel();
|
||||
// 取消事件监听
|
||||
// 取消事件监听 [AUTO-TRANSLATED:c722acb6]
|
||||
// Cancel event listening
|
||||
NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
|
||||
|
||||
// 切换到自己的线程再回复
|
||||
// 切换到自己的线程再回复 [AUTO-TRANSLATED:3b630c64]
|
||||
// Switch to your own thread and then reply
|
||||
strongSelf->_poller->async([weakSelf, cb]() {
|
||||
if (auto strongSelf = weakSelf.lock()) {
|
||||
// 再找一遍媒体源,一般能找到
|
||||
// 再找一遍媒体源,一般能找到 [AUTO-TRANSLATED:f0b81977]
|
||||
// Find the media source again, usually you can find it
|
||||
strongSelf->findAsync(0, cb);
|
||||
}
|
||||
}, false);
|
||||
};
|
||||
// 监听媒体注册事件
|
||||
// 监听媒体注册事件 [AUTO-TRANSLATED:ea3e763b]
|
||||
// Listen to media registration events
|
||||
NoticeCenter::Instance().addListener(listener_tag, Broadcast::kBroadcastMediaChanged, onRegist);
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时检查媒体是否在线
|
||||
* Check if the media is online regularly
|
||||
|
||||
* [AUTO-TRANSLATED:11bae8ab]
|
||||
*/
|
||||
void FFmpegSource::startTimer(int timeout_ms) {
|
||||
weak_ptr<FFmpegSource> weakSelf = shared_from_this();
|
||||
@ -212,54 +236,66 @@ void FFmpegSource::startTimer(int timeout_ms) {
|
||||
_timer = std::make_shared<Timer>(1.0f, [weakSelf, timeout_ms]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
//自身已经销毁
|
||||
// 自身已经销毁 [AUTO-TRANSLATED:5a02ef8b]
|
||||
// Self has been destroyed
|
||||
return false;
|
||||
}
|
||||
bool needRestart = ffmpeg_restart_sec > 0 && strongSelf->_replay_ticker.elapsedTime() > ffmpeg_restart_sec * 1000;
|
||||
if (is_local_ip(strongSelf->_media_info.host)) {
|
||||
// 推流给自己的,我们通过检查是否已经注册来判断FFmpeg是否工作正常
|
||||
// 推流给自己的,我们通过检查是否已经注册来判断FFmpeg是否工作正常 [AUTO-TRANSLATED:9a441d38]
|
||||
// Push stream to yourself, we judge whether FFmpeg is working properly by checking whether it has been registered
|
||||
strongSelf->findAsync(0, [&](const MediaSource::Ptr &src) {
|
||||
// 同步查找流
|
||||
// 同步查找流 [AUTO-TRANSLATED:97048f1e]
|
||||
// Synchronously find the stream
|
||||
if (!src || needRestart) {
|
||||
if (needRestart) {
|
||||
strongSelf->_replay_ticker.resetTime();
|
||||
if (strongSelf->_process.wait(false)) {
|
||||
// FFmpeg进程还在运行,超时就关闭它
|
||||
// FFmpeg进程还在运行,超时就关闭它 [AUTO-TRANSLATED:bd907d0c]
|
||||
// The FFmpeg process is still running, timeout and close it
|
||||
strongSelf->_process.kill(2000);
|
||||
}
|
||||
InfoL << "FFmpeg即将重启, 将会继续拉流 " << strongSelf->_src_url;
|
||||
}
|
||||
// 流不在线,重新拉流, 这里原先是10秒超时,实际发现10秒不够,改成20秒了
|
||||
// 流不在线,重新拉流, 这里原先是10秒超时,实际发现10秒不够,改成20秒了 [AUTO-TRANSLATED:10e8c704]
|
||||
// The stream is not online, re-pull the stream, here the original timeout was 10 seconds, but it was found that 10 seconds was not enough, so it was changed to 20 seconds
|
||||
if (strongSelf->_replay_ticker.elapsedTime() > 20 * 1000) {
|
||||
// 上次重试时间超过10秒,那么再重试FFmpeg拉流
|
||||
// 上次重试时间超过10秒,那么再重试FFmpeg拉流 [AUTO-TRANSLATED:b308095a]
|
||||
// The last retry time exceeds 10 seconds, then retry FFmpeg to pull the stream
|
||||
strongSelf->_replay_ticker.resetTime();
|
||||
strongSelf->play(strongSelf->_ffmpeg_cmd_key, strongSelf->_src_url, strongSelf->_dst_url, timeout_ms, [](const SockException &) {});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 推流给其他服务器的,我们通过判断FFmpeg进程是否在线,如果FFmpeg推流中断,那么它应该会自动退出
|
||||
// 推流给其他服务器的,我们通过判断FFmpeg进程是否在线,如果FFmpeg推流中断,那么它应该会自动退出 [AUTO-TRANSLATED:82da3ea5]
|
||||
// Push stream to other servers, we judge whether the FFmpeg process is online, if FFmpeg push stream is interrupted, then it should exit automatically
|
||||
if (!strongSelf->_process.wait(false) || needRestart) {
|
||||
if (needRestart) {
|
||||
strongSelf->_replay_ticker.resetTime();
|
||||
if (strongSelf->_process.wait(false)) {
|
||||
// FFmpeg进程还在运行,超时就关闭它
|
||||
// FFmpeg进程还在运行,超时就关闭它 [AUTO-TRANSLATED:bd907d0c]
|
||||
// The FFmpeg process is still running, timeout and close it
|
||||
strongSelf->_process.kill(2000);
|
||||
}
|
||||
InfoL << "FFmpeg即将重启, 将会继续拉流 " << strongSelf->_src_url;
|
||||
}
|
||||
// ffmpeg不在线,重新拉流
|
||||
// ffmpeg不在线,重新拉流 [AUTO-TRANSLATED:aa958c43]
|
||||
// ffmpeg is not online, re-pull the stream
|
||||
strongSelf->play(strongSelf->_ffmpeg_cmd_key, strongSelf->_src_url, strongSelf->_dst_url, timeout_ms, [weakSelf](const SockException &ex) {
|
||||
if (!ex) {
|
||||
// 没有错误
|
||||
// 没有错误 [AUTO-TRANSLATED:037ae0ca]
|
||||
// No error
|
||||
return;
|
||||
}
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
// 自身已经销毁
|
||||
// 自身已经销毁 [AUTO-TRANSLATED:5f954f8a]
|
||||
// Self has been destroyed
|
||||
return;
|
||||
}
|
||||
// 上次重试时间超过10秒,那么再重试FFmpeg拉流
|
||||
// 上次重试时间超过10秒,那么再重试FFmpeg拉流 [AUTO-TRANSLATED:b308095a]
|
||||
// Retry FFmpeg stream pulling if the last retry time is over 10 seconds
|
||||
strongSelf->startTimer(10 * 1000);
|
||||
});
|
||||
}
|
||||
@ -275,10 +311,12 @@ void FFmpegSource::setOnClose(const function<void()> &cb){
|
||||
bool FFmpegSource::close(MediaSource &sender) {
|
||||
auto listener = getDelegate();
|
||||
if (listener && !listener->close(sender)) {
|
||||
//关闭失败
|
||||
// 关闭失败 [AUTO-TRANSLATED:83f07dba]
|
||||
// Close failed
|
||||
return false;
|
||||
}
|
||||
//该流无人观看,我们停止吧
|
||||
// 该流无人观看,我们停止吧 [AUTO-TRANSLATED:43999b39]
|
||||
// No one is watching this stream, let's stop it
|
||||
if (_onClose) {
|
||||
_onClose();
|
||||
}
|
||||
@ -297,7 +335,8 @@ void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) {
|
||||
auto muxer = src->getMuxer();
|
||||
auto listener = muxer ? muxer->getDelegate() : nullptr;
|
||||
if (listener && listener.get() != this) {
|
||||
//防止多次进入onGetMediaSource函数导致无限递归调用的bug
|
||||
// 防止多次进入onGetMediaSource函数导致无限递归调用的bug [AUTO-TRANSLATED:ceadb9c7]
|
||||
// Prevent the bug of infinite recursive calls caused by entering the onGetMediaSource function multiple times
|
||||
setDelegate(listener);
|
||||
muxer->setDelegate(shared_from_this());
|
||||
if (_enable_hls) {
|
||||
@ -317,7 +356,8 @@ void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float
|
||||
WorkThreadPool::Instance().getPoller()->async([timeout_sec, play_url, save_path, cb, ticker]() {
|
||||
auto elapsed_ms = ticker.elapsedTime();
|
||||
if (elapsed_ms > timeout_sec * 1000) {
|
||||
// 超时,后台线程负载太高,当代太久才启动该任务
|
||||
// 超时,后台线程负载太高,当代太久才启动该任务 [AUTO-TRANSLATED:815606d6]
|
||||
// Timeout, the background thread load is too high, it takes too long to start this task
|
||||
cb(false, "wait work poller schedule snap task timeout");
|
||||
return;
|
||||
}
|
||||
@ -328,21 +368,26 @@ void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float
|
||||
auto log_file = ffmpeg_log.empty() ? ffmpeg_log : File::absolutePath("", ffmpeg_log);
|
||||
process->run(cmd, log_file);
|
||||
|
||||
//定时器延时应该减去后台任务启动的延时
|
||||
// 定时器延时应该减去后台任务启动的延时 [AUTO-TRANSLATED:7d224687]
|
||||
// The timer delay should be reduced by the delay of the background task startup
|
||||
auto delayTask = EventPollerPool::Instance().getPoller()->doDelayTask(
|
||||
(uint64_t)(timeout_sec * 1000 - elapsed_ms), [process, cb, log_file, save_path]() {
|
||||
if (process->wait(false)) {
|
||||
// FFmpeg进程还在运行,超时就关闭它
|
||||
// FFmpeg进程还在运行,超时就关闭它 [AUTO-TRANSLATED:bd907d0c]
|
||||
// The FFmpeg process is still running, close it if it times out
|
||||
process->kill(2000);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// 等待FFmpeg进程退出
|
||||
// 等待FFmpeg进程退出 [AUTO-TRANSLATED:0a179187]
|
||||
// Wait for the FFmpeg process to exit
|
||||
process->wait(true);
|
||||
// FFmpeg进程退出了可以取消定时器了
|
||||
// FFmpeg进程退出了可以取消定时器了 [AUTO-TRANSLATED:c8a4b513]
|
||||
// The FFmpeg process has exited, the timer can be canceled
|
||||
delayTask->cancel();
|
||||
// 执行回调函数
|
||||
// 执行回调函数 [AUTO-TRANSLATED:7309a900]
|
||||
// Execute the callback function
|
||||
bool success = process->exit_code() == 0 && File::fileSize(save_path);
|
||||
cb(success, (!success && !log_file.empty()) ? File::loadFile(log_file) : "");
|
||||
});
|
||||
|
@ -26,11 +26,16 @@ namespace FFmpeg {
|
||||
class FFmpegSnap {
|
||||
public:
|
||||
using onSnap = std::function<void(bool success, const std::string &err_msg)>;
|
||||
/// 创建截图
|
||||
/// \param play_url 播放url地址,只要FFmpeg支持即可
|
||||
/// \param save_path 截图jpeg文件保存路径
|
||||
/// \param timeout_sec 生成截图超时时间(防止阻塞太久)
|
||||
/// \param cb 生成截图成功与否回调
|
||||
// / 创建截图 [AUTO-TRANSLATED:6d334c49]
|
||||
// / Create a screenshot
|
||||
// / \param play_url 播放url地址,只要FFmpeg支持即可 [AUTO-TRANSLATED:609d4de4]
|
||||
// / \param play_url The playback URL address, as long as FFmpeg supports it
|
||||
// / \param save_path 截图jpeg文件保存路径 [AUTO-TRANSLATED:0fc0ac0d]
|
||||
// / \param save_path The path to save the screenshot JPEG file
|
||||
// / \param timeout_sec 生成截图超时时间(防止阻塞太久) [AUTO-TRANSLATED:0dcc0095]
|
||||
// / \param timeout_sec Timeout for generating the screenshot (to prevent blocking for too long)
|
||||
// / \param cb 生成截图成功与否回调 [AUTO-TRANSLATED:5b4b93c9]
|
||||
// / \param cb Callback for whether the screenshot was generated successfully
|
||||
static void makeSnap(const std::string &play_url, const std::string &save_path, float timeout_sec, const onSnap &cb);
|
||||
|
||||
private:
|
||||
@ -48,6 +53,9 @@ public:
|
||||
|
||||
/**
|
||||
* 设置主动关闭回调
|
||||
* Set the active close callback
|
||||
|
||||
* [AUTO-TRANSLATED:2134a5b3]
|
||||
*/
|
||||
void setOnClose(const std::function<void()> &cb);
|
||||
|
||||
@ -58,6 +66,14 @@ public:
|
||||
* @param dst_url FFmpeg推流地址
|
||||
* @param timeout_ms 等待结果超时时间,单位毫秒
|
||||
* @param cb 成功与否回调
|
||||
* Start playing the URL
|
||||
* @param ffmpeg_cmd_key FFmpeg stream command configuration item key, users can set multiple command parameter templates in the configuration file at the same time
|
||||
* @param src_url FFmpeg stream address
|
||||
* @param dst_url FFmpeg push stream address
|
||||
* @param timeout_ms Timeout for waiting for the result, in milliseconds
|
||||
* @param cb Success or failure callback
|
||||
|
||||
* [AUTO-TRANSLATED:2c35789e]
|
||||
*/
|
||||
void play(const std::string &ffmpeg_cmd_key, const std::string &src_url, const std::string &dst_url, int timeout_ms, const onPlay &cb);
|
||||
|
||||
@ -65,6 +81,11 @@ public:
|
||||
* 设置录制
|
||||
* @param enable_hls 是否开启hls直播或录制
|
||||
* @param enable_mp4 是否录制mp4
|
||||
* Set recording
|
||||
* @param enable_hls Whether to enable HLS live streaming or recording
|
||||
* @param enable_mp4 Whether to record MP4
|
||||
|
||||
* [AUTO-TRANSLATED:9f28d5c2]
|
||||
*/
|
||||
void setupRecordFlag(bool enable_hls, bool enable_mp4);
|
||||
|
||||
@ -74,11 +95,14 @@ private:
|
||||
void onGetMediaSource(const mediakit::MediaSource::Ptr &src);
|
||||
|
||||
///////MediaSourceEvent override///////
|
||||
// 关闭
|
||||
// 关闭 [AUTO-TRANSLATED:92392f02]
|
||||
// Close
|
||||
bool close(mediakit::MediaSource &sender) override;
|
||||
// 获取媒体源类型
|
||||
// 获取媒体源类型 [AUTO-TRANSLATED:34290a69]
|
||||
// Get the media source type
|
||||
mediakit::MediaOriginType getOriginType(mediakit::MediaSource &sender) const override;
|
||||
//获取媒体源url或者文件路径
|
||||
// 获取媒体源url或者文件路径 [AUTO-TRANSLATED:d6d885b8]
|
||||
// Get the media source URL or file path
|
||||
std::string getOriginUrl(mediakit::MediaSource &sender) const override;
|
||||
|
||||
private:
|
||||
|
@ -35,12 +35,15 @@ using namespace toolkit;
|
||||
#ifndef _WIN32
|
||||
|
||||
static void setupChildProcess() {
|
||||
//取消cpu亲和性设置,防止FFmpeg进程cpu占用率不能超过100%的问题
|
||||
// 取消cpu亲和性设置,防止FFmpeg进程cpu占用率不能超过100%的问题 [AUTO-TRANSLATED:d168129d]
|
||||
// Cancel CPU affinity settings to prevent FFmpeg process from exceeding 100% CPU usage.
|
||||
setThreadAffinity(-1);
|
||||
//子进程关闭core文件生成
|
||||
// 子进程关闭core文件生成 [AUTO-TRANSLATED:721d2925]
|
||||
// Disable core file generation for child processes.
|
||||
struct rlimit rlim = { 0, 0 };
|
||||
setrlimit(RLIMIT_CORE, &rlim);
|
||||
//子进程恢复默认信号处理
|
||||
// 子进程恢复默认信号处理 [AUTO-TRANSLATED:1bc7387b]
|
||||
// Restore default signal handling for child processes.
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
@ -52,7 +55,8 @@ static int runChildProcess(string cmd, string log_file) {
|
||||
setupChildProcess();
|
||||
|
||||
if (log_file.empty()) {
|
||||
//未指定子进程日志文件时,重定向至/dev/null
|
||||
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
|
||||
// Redirect child process logs to /dev/null if no log file is specified.
|
||||
log_file = "/dev/null";
|
||||
} else {
|
||||
log_file = StrPrinter << log_file << "." << getpid();
|
||||
@ -64,7 +68,8 @@ static int runChildProcess(string cmd, string log_file) {
|
||||
open("/dev/null", O_RDONLY, 0666); /* will be fd 0 (STDIN_FILENO) */
|
||||
}
|
||||
|
||||
//重定向shell日志至文件
|
||||
// 重定向shell日志至文件 [AUTO-TRANSLATED:3480502b]
|
||||
// Redirect shell logs to file.
|
||||
auto fp = File::create_file(log_file, "ab");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), get_uv_error(), get_uv_errmsg());
|
||||
@ -77,7 +82,8 @@ static int runChildProcess(string cmd, string log_file) {
|
||||
if (dup2(log_fd, STDERR_FILENO) < 0) {
|
||||
fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), get_uv_error(), get_uv_errmsg());
|
||||
}
|
||||
// 关闭日志文件
|
||||
// 关闭日志文件 [AUTO-TRANSLATED:9fb6e256]
|
||||
// Close log file.
|
||||
::fclose(fp);
|
||||
}
|
||||
fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data());
|
||||
@ -114,13 +120,15 @@ void Process::run(const string &cmd, string log_file) {
|
||||
STARTUPINFO si = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
if (log_file.empty()) {
|
||||
//未指定子进程日志文件时,重定向至/dev/null
|
||||
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
|
||||
// Redirect child process logs to /dev/null if no log file is specified.
|
||||
log_file = "NUL";
|
||||
} else {
|
||||
log_file = StrPrinter << log_file << "." << getCurrentMillisecond();
|
||||
}
|
||||
|
||||
//重定向shell日志至文件
|
||||
// 重定向shell日志至文件 [AUTO-TRANSLATED:3480502b]
|
||||
// Redirect shell logs to file.
|
||||
auto fp = File::create_file(log_file, "ab");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), get_uv_error(), get_uv_errmsg());
|
||||
@ -137,7 +145,8 @@ void Process::run(const string &cmd, string log_file) {
|
||||
|
||||
LPTSTR lpDir = const_cast<char *>(cmd.data());
|
||||
if (CreateProcess(NULL, lpDir, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
|
||||
//下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
|
||||
// 下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 [AUTO-TRANSLATED:d50fada2]
|
||||
// The following two lines close the handle and break the relationship between the current process and the new process. Otherwise, the TerminateProcess function may accidentally close the child process.
|
||||
CloseHandle(pi.hThread);
|
||||
_pid = pi.dwProcessId;
|
||||
_handle = pi.hProcess;
|
||||
@ -165,12 +174,14 @@ void Process::run(const string &cmd, string log_file) {
|
||||
throw std::runtime_error(StrPrinter << "fork child process failed, cmd: " << cmd << ",err:" << get_uv_errmsg());
|
||||
}
|
||||
if (_pid == 0) {
|
||||
//子进程
|
||||
// 子进程 [AUTO-TRANSLATED:3f793797]
|
||||
// Child process.
|
||||
exit(runChildProcess(cmd, log_file));
|
||||
}
|
||||
#endif
|
||||
if (log_file.empty()) {
|
||||
//未指定子进程日志文件时,重定向至/dev/null
|
||||
// 未指定子进程日志文件时,重定向至/dev/null [AUTO-TRANSLATED:dd0c9853]
|
||||
// Redirect child process logs to /dev/null if no log file is specified.
|
||||
log_file = "/dev/null";
|
||||
} else {
|
||||
log_file = StrPrinter << log_file << "." << _pid;
|
||||
@ -185,6 +196,13 @@ void Process::run(const string &cmd, string log_file) {
|
||||
* @param exit_code_ptr 进程返回代码
|
||||
* @param block 是否阻塞等待
|
||||
* @return 进程是否还在运行
|
||||
* Get the process's alive status.
|
||||
* @param pid Process ID
|
||||
* @param exit_code_ptr Process return code
|
||||
* @param block Whether to block and wait
|
||||
* @return Whether the process is still running
|
||||
|
||||
* [AUTO-TRANSLATED:ef80ff17]
|
||||
*/
|
||||
static bool s_wait(pid_t pid, void *handle, int *exit_code_ptr, bool block) {
|
||||
if (pid <= 0) {
|
||||
@ -193,14 +211,16 @@ static bool s_wait(pid_t pid, void *handle, int *exit_code_ptr, bool block) {
|
||||
#ifdef _WIN32
|
||||
DWORD code = 0;
|
||||
if (block) {
|
||||
//一直等待
|
||||
// 一直等待 [AUTO-TRANSLATED:ca8a5e14]
|
||||
// Wait indefinitely.
|
||||
code = WaitForSingleObject(handle, INFINITE);
|
||||
} else {
|
||||
code = WaitForSingleObject(handle, 0);
|
||||
}
|
||||
|
||||
if (code == WAIT_FAILED || code == WAIT_OBJECT_0) {
|
||||
//子进程已经退出了,获取子进程退出代码
|
||||
// 子进程已经退出了,获取子进程退出代码 [AUTO-TRANSLATED:c39663b2]
|
||||
// The child process has exited, get the child process exit code.
|
||||
DWORD exitCode = 0;
|
||||
if (exit_code_ptr && GetExitCodeProcess(handle, &exitCode)) {
|
||||
*exit_code_ptr = exitCode;
|
||||
@ -209,10 +229,12 @@ static bool s_wait(pid_t pid, void *handle, int *exit_code_ptr, bool block) {
|
||||
}
|
||||
|
||||
if (code == WAIT_TIMEOUT) {
|
||||
//子进程还在线
|
||||
// 子进程还在线 [AUTO-TRANSLATED:3d32ef56]
|
||||
// The child process is still online.
|
||||
return true;
|
||||
}
|
||||
//不太可能运行到此处
|
||||
// 不太可能运行到此处 [AUTO-TRANSLATED:b1fde65d]
|
||||
// It is unlikely to run to this point.
|
||||
WarnL << "WaitForSingleObject ret:" << code;
|
||||
return false;
|
||||
#else
|
||||
@ -268,42 +290,52 @@ bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent) {
|
||||
|
||||
static void s_kill(pid_t pid, void *handle, int max_delay, bool force) {
|
||||
if (pid <= 0) {
|
||||
// pid无效
|
||||
// pid无效 [AUTO-TRANSLATED:6665d7a0]
|
||||
// Invalid pid.
|
||||
return;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// windows下目前没有比较好的手段往子进程发送SIGTERM或信号
|
||||
//所以杀死子进程的方式全部强制为立即关闭
|
||||
// windows下目前没有比较好的手段往子进程发送SIGTERM或信号 [AUTO-TRANSLATED:cd32ad25]
|
||||
// Currently, there is no good way to send SIGTERM or signals to child processes under Windows.
|
||||
// 所以杀死子进程的方式全部强制为立即关闭 [AUTO-TRANSLATED:2fc31f2b]
|
||||
// Therefore, all methods of killing child processes are forced to be immediate closure.
|
||||
force = true;
|
||||
if (force) {
|
||||
//强制关闭子进程
|
||||
// 强制关闭子进程 [AUTO-TRANSLATED:f3c712f6]
|
||||
// Force close the child process.
|
||||
TerminateProcess(handle, 0);
|
||||
} else {
|
||||
//非强制关闭,发送Ctr+C信号
|
||||
// 非强制关闭,发送Ctr+C信号 [AUTO-TRANSLATED:fe9bf53f]
|
||||
// Non-forced closure, send Ctrl+C signal.
|
||||
signalCtrl(pid, CTRL_C_EVENT);
|
||||
}
|
||||
#else
|
||||
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
|
||||
//进程可能已经退出了
|
||||
// 进程可能已经退出了 [AUTO-TRANSLATED:682a8b61]
|
||||
// The process may have already exited.
|
||||
WarnL << "kill process " << pid << " failed:" << get_uv_errmsg();
|
||||
return;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
if (force) {
|
||||
//发送SIGKILL信号后,阻塞等待退出
|
||||
// 发送SIGKILL信号后,阻塞等待退出 [AUTO-TRANSLATED:4fc03dae]
|
||||
// After sending the SIGKILL signal, block and wait for exit.
|
||||
s_wait(pid, handle, nullptr, true);
|
||||
DebugL << "force kill " << pid << " success!";
|
||||
return;
|
||||
}
|
||||
|
||||
//发送SIGTERM信号后,2秒后检查子进程是否已经退出
|
||||
// 发送SIGTERM信号后,2秒后检查子进程是否已经退出 [AUTO-TRANSLATED:b9878b28]
|
||||
// After sending the SIGTERM signal, check if the child process has exited after 2 seconds.
|
||||
EventPollerPool::Instance().getPoller()->doDelayTask(max_delay, [pid, handle]() {
|
||||
if (!s_wait(pid, handle, nullptr, false)) {
|
||||
//进程已经退出了
|
||||
// 进程已经退出了 [AUTO-TRANSLATED:ad02bb63]
|
||||
// The process has exited.
|
||||
return 0;
|
||||
}
|
||||
//进程还在运行
|
||||
// 进程还在运行 [AUTO-TRANSLATED:b1aa9ba4]
|
||||
// The process is still running.
|
||||
WarnL << "process still working,force kill it:" << pid;
|
||||
s_kill(pid, handle, 0, true);
|
||||
return 0;
|
||||
|
@ -134,17 +134,20 @@ void System::startDaemon(bool &kill_parent_if_failed) {
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
WarnL << "fork失败:" << get_uv_errmsg();
|
||||
//休眠1秒再试
|
||||
// 休眠1秒再试 [AUTO-TRANSLATED:00e5d7bf]
|
||||
// Sleep for 1 second and try again
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
//子进程
|
||||
// 子进程 [AUTO-TRANSLATED:3f793797]
|
||||
// Child process
|
||||
return;
|
||||
}
|
||||
|
||||
//父进程,监视子进程是否退出
|
||||
// 父进程,监视子进程是否退出 [AUTO-TRANSLATED:0e13a34d]
|
||||
// Parent process, monitor whether the child process exits
|
||||
DebugL << "启动子进程:" << pid;
|
||||
signal(SIGINT, [](int) {
|
||||
WarnL << "收到主动退出信号,关闭父进程与子进程";
|
||||
@ -162,9 +165,11 @@ void System::startDaemon(bool &kill_parent_if_failed) {
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) >= 0) {
|
||||
WarnL << "子进程退出";
|
||||
//休眠3秒再启动子进程
|
||||
// 休眠3秒再启动子进程 [AUTO-TRANSLATED:608448bd]
|
||||
// Sleep for 3 seconds and then start the child process
|
||||
sleep(3);
|
||||
//重启子进程,如果子进程重启失败,那么不应该杀掉守护进程,这样守护进程可以一直尝试重启子进程
|
||||
// 重启子进程,如果子进程重启失败,那么不应该杀掉守护进程,这样守护进程可以一直尝试重启子进程 [AUTO-TRANSLATED:0a336b0a]
|
||||
// Restart the child process. If the child process fails to restart, the daemon process should not be killed. This allows the daemon process to continuously attempt to restart the child process.
|
||||
kill_parent_if_failed = false;
|
||||
break;
|
||||
}
|
||||
@ -204,7 +209,8 @@ void System::systemSetup(){
|
||||
#ifndef ANDROID
|
||||
signal(SIGSEGV, sig_crash);
|
||||
signal(SIGABRT, sig_crash);
|
||||
//忽略挂起信号
|
||||
// 忽略挂起信号 [AUTO-TRANSLATED:73e71e54]
|
||||
// Ignore the hang up signal
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
#endif// ANDROID
|
||||
#endif//!defined(_WIN32)
|
||||
|
@ -80,14 +80,17 @@ void Channel::copyData(const mediakit::FFmpegFrame::Ptr& buf, const Param::Ptr&
|
||||
memcpy(buf->get()->data[0] + buf->get()->linesize[0] * (i + p->posY) + p->posX,
|
||||
_tmp->get()->data[0] + _tmp->get()->linesize[0] * i, _tmp->get()->width);
|
||||
}
|
||||
// 确保height为奇数时,也能正确的复制到最后一行uv数据
|
||||
// 确保height为奇数时,也能正确的复制到最后一行uv数据 [AUTO-TRANSLATED:69895ea5]
|
||||
// Ensure that the uv data can be copied to the last line correctly when height is odd
|
||||
for (int i = 0; i < (p->height + 1) / 2; i++) {
|
||||
// U平面
|
||||
// U平面 [AUTO-TRANSLATED:8b73dc2d]
|
||||
// U plane
|
||||
memcpy(buf->get()->data[1] + buf->get()->linesize[1] * (i + p->posY / 2) +
|
||||
p->posX / 2,
|
||||
_tmp->get()->data[1] + _tmp->get()->linesize[1] * i, _tmp->get()->width / 2);
|
||||
|
||||
// V平面
|
||||
// V平面 [AUTO-TRANSLATED:8fa72cc7]
|
||||
// V plane
|
||||
memcpy(buf->get()->data[2] + buf->get()->linesize[2] * (i + p->posY / 2) +
|
||||
p->posX / 2,
|
||||
_tmp->get()->data[2] + _tmp->get()->linesize[2] * i, _tmp->get()->width / 2);
|
||||
@ -95,7 +98,8 @@ void Channel::copyData(const mediakit::FFmpegFrame::Ptr& buf, const Param::Ptr&
|
||||
break;
|
||||
}
|
||||
case AV_PIX_FMT_NV12: {
|
||||
// TODO: 待实现
|
||||
// TODO: 待实现 [AUTO-TRANSLATED:247ec1df]
|
||||
// TODO: To be implemented
|
||||
break;
|
||||
}
|
||||
|
||||
@ -110,7 +114,8 @@ void StackPlayer::addChannel(const std::weak_ptr<Channel>& chn) {
|
||||
void StackPlayer::play() {
|
||||
|
||||
auto url = _url;
|
||||
// 创建拉流 解码对象
|
||||
// 创建拉流 解码对象 [AUTO-TRANSLATED:9267c5dc]
|
||||
// Create a pull stream decoding object
|
||||
_player = std::make_shared<mediakit::MediaPlayer>();
|
||||
std::weak_ptr<mediakit::MediaPlayer> weakPlayer = _player;
|
||||
|
||||
@ -127,7 +132,8 @@ void StackPlayer::play() {
|
||||
if (!self) { return; }
|
||||
|
||||
if (!ex) {
|
||||
// 取消定时器
|
||||
// 取消定时器 [AUTO-TRANSLATED:41ff7c9a]
|
||||
// Cancel the timer
|
||||
self->_timer.reset();
|
||||
self->_failedCount = 0;
|
||||
|
||||
@ -141,7 +147,8 @@ void StackPlayer::play() {
|
||||
// auto audioTrack = std::dynamic_pointer_cast<mediakit::AudioTrack>(strongPlayer->getTrack(mediakit::TrackAudio, false));
|
||||
|
||||
if (videoTrack) {
|
||||
// TODO:添加使用显卡还是cpu解码的判断逻辑
|
||||
// TODO:添加使用显卡还是cpu解码的判断逻辑 [AUTO-TRANSLATED:44bef37a]
|
||||
// TODO: Add logic to determine whether to use GPU or CPU decoding
|
||||
auto decoder = std::make_shared<mediakit::FFmpegDecoder>(
|
||||
videoTrack, 0, std::vector<std::string>{"h264", "hevc"});
|
||||
|
||||
@ -227,7 +234,8 @@ VideoStack::VideoStack(const std::string& id, int width, int height, AVPixelForm
|
||||
info.iBitRate = _bitRate;
|
||||
|
||||
_dev->initVideo(info);
|
||||
// dev->initAudio(); //TODO:音频
|
||||
// dev->initAudio(); //TODO:音频 [AUTO-TRANSLATED:adc5658b]
|
||||
// dev->initAudio(); //TODO: Audio
|
||||
_dev->addTrackCompleted();
|
||||
|
||||
_isExit = false;
|
||||
@ -276,7 +284,8 @@ void VideoStack::start() {
|
||||
}
|
||||
|
||||
void VideoStack::initBgColor() {
|
||||
// 填充底色
|
||||
// 填充底色 [AUTO-TRANSLATED:ee9bbd46]
|
||||
// Fill the background color
|
||||
auto R = 20;
|
||||
auto G = 20;
|
||||
auto B = 20;
|
||||
@ -402,11 +411,13 @@ Params VideoStackManager::parseParams(const Json::Value& json, std::string& id,
|
||||
float gapv = json["gapv"].asFloat();// 垂直间距
|
||||
float gaph = json["gaph"].asFloat();// 水平间距
|
||||
|
||||
// 单个间距
|
||||
// 单个间距 [AUTO-TRANSLATED:e1b9b5b6]
|
||||
// Single spacing
|
||||
int gaphPix = static_cast<int>(round(width * gaph));
|
||||
int gapvPix = static_cast<int>(round(height * gapv));
|
||||
|
||||
// 根据间距计算格子宽高
|
||||
// 根据间距计算格子宽高 [AUTO-TRANSLATED:b9972498]
|
||||
// Calculate the width and height of the grid according to the spacing
|
||||
int gridWidth = cols > 1 ? (width - gaphPix * (cols - 1)) / cols : width;
|
||||
int gridHeight = rows > 1 ? (height - gapvPix * (rows - 1)) / rows : height;
|
||||
|
||||
@ -427,7 +438,8 @@ Params VideoStackManager::parseParams(const Json::Value& json, std::string& id,
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否需要合并格子 (焦点屏)
|
||||
// 判断是否需要合并格子 (焦点屏) [AUTO-TRANSLATED:bfa14430]
|
||||
// Determine whether to merge grids (focus screen)
|
||||
if (json.isMember("span") && json["span"].isArray() && json["span"].size() > 0) {
|
||||
for (const auto& subArray : json["span"]) {
|
||||
if (!subArray.isArray() || subArray.size() != 2) {
|
||||
|
@ -98,7 +98,8 @@ private:
|
||||
std::string _url;
|
||||
mediakit::MediaPlayer::Ptr _player;
|
||||
|
||||
// 用于断线重连
|
||||
// 用于断线重连 [AUTO-TRANSLATED:18fd242a]
|
||||
// Used for disconnection and reconnection
|
||||
toolkit::Timer::Ptr _timer;
|
||||
int _failedCount = 0;
|
||||
|
||||
@ -145,13 +146,16 @@ private:
|
||||
|
||||
class VideoStackManager {
|
||||
public:
|
||||
// 创建拼接流
|
||||
// 创建拼接流 [AUTO-TRANSLATED:ebb3a8ec]
|
||||
// Create a concatenated stream
|
||||
int startVideoStack(const Json::Value& json);
|
||||
|
||||
// 停止拼接流
|
||||
// 停止拼接流 [AUTO-TRANSLATED:a46f341f]
|
||||
// Stop the concatenated stream
|
||||
int stopVideoStack(const std::string& id);
|
||||
|
||||
// 可以在不断流的情况下,修改拼接流的配置(实现切换拼接屏内容)
|
||||
// 可以在不断流的情况下,修改拼接流的配置(实现切换拼接屏内容) [AUTO-TRANSLATED:f9b59b6b]
|
||||
// You can modify the configuration of the concatenated stream (to switch the content of the concatenated screen) without stopping the stream
|
||||
int resetVideoStack(const Json::Value& json);
|
||||
|
||||
public:
|
||||
|
@ -90,7 +90,8 @@ static onceToken token([]() {
|
||||
}//namespace API
|
||||
|
||||
using HttpApi = function<void(const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, SockInfo &sender)>;
|
||||
//http api列表
|
||||
// http api列表 [AUTO-TRANSLATED:a05e9d9d]
|
||||
// http api list
|
||||
static map<string, HttpApi, StrCaseCompare> s_map_api;
|
||||
|
||||
static void responseApi(const Json::Value &res, const HttpSession::HttpResponseInvoker &invoker){
|
||||
@ -118,7 +119,8 @@ static HttpApi toApi(const function<void(API_ARGS_MAP_ASYNC)> &cb) {
|
||||
Json::Value val;
|
||||
val["code"] = API::Success;
|
||||
|
||||
//参数解析成map
|
||||
// 参数解析成map [AUTO-TRANSLATED:20e11ff3]
|
||||
// Parse parameters into a map
|
||||
auto args = getAllArgs(parser);
|
||||
cb(sender, headerOut, ArgsMap(parser, args), val, invoker);
|
||||
};
|
||||
@ -143,7 +145,8 @@ static HttpApi toApi(const function<void(API_ARGS_JSON_ASYNC)> &cb) {
|
||||
if (parser["Content-Type"].find("application/json") == string::npos) {
|
||||
throw InvalidArgsException("该接口只支持json格式的请求");
|
||||
}
|
||||
//参数解析成json对象然后处理
|
||||
// 参数解析成json对象然后处理 [AUTO-TRANSLATED:6f23397b]
|
||||
// Parse parameters into a JSON object and then process
|
||||
Json::Value args;
|
||||
Json::Reader reader;
|
||||
reader.parse(parser.content(), args);
|
||||
@ -203,7 +206,8 @@ void api_regist(const string &api_path, const function<void(API_ARGS_STRING_ASYN
|
||||
s_map_api.emplace(api_path, toApi(func));
|
||||
}
|
||||
|
||||
//获取HTTP请求中url参数、content参数
|
||||
// 获取HTTP请求中url参数、content参数 [AUTO-TRANSLATED:d161a1e1]
|
||||
// Get URL parameters and content parameters from the HTTP request
|
||||
static ApiArgsType getAllArgs(const Parser &parser) {
|
||||
ApiArgsType allArgs;
|
||||
if (parser["Content-Type"].find("application/x-www-form-urlencoded") == 0) {
|
||||
@ -245,21 +249,25 @@ static void *web_api_tag = nullptr;
|
||||
|
||||
static inline void addHttpListener(){
|
||||
GET_CONFIG(bool, api_debug, API::kApiDebug);
|
||||
//注册监听kBroadcastHttpRequest事件
|
||||
// 注册监听kBroadcastHttpRequest事件 [AUTO-TRANSLATED:4af22c90]
|
||||
// Register to listen for the kBroadcastHttpRequest event
|
||||
NoticeCenter::Instance().addListener(&web_api_tag, Broadcast::kBroadcastHttpRequest, [](BroadcastHttpRequestArgs) {
|
||||
auto it = s_map_api.find(parser.url());
|
||||
if (it == s_map_api.end()) {
|
||||
return;
|
||||
}
|
||||
//该api已被消费
|
||||
// 该api已被消费 [AUTO-TRANSLATED:db0872fc]
|
||||
// This API has been consumed
|
||||
consumed = true;
|
||||
|
||||
if(api_debug){
|
||||
auto newInvoker = [invoker, parser](int code, const HttpSession::KeyValue &headerOut, const HttpBody::Ptr &body) {
|
||||
//body默认为空
|
||||
// body默认为空 [AUTO-TRANSLATED:4fd4ecc8]
|
||||
// The body is empty by default
|
||||
ssize_t size = 0;
|
||||
if (body && body->remainSize()) {
|
||||
//有body,获取body大小
|
||||
// 有body,获取body大小 [AUTO-TRANSLATED:ab1c417d]
|
||||
// If there is a body, get the body size
|
||||
size = body->remainSize();
|
||||
}
|
||||
|
||||
@ -362,17 +370,21 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//拉流代理器列表
|
||||
// 拉流代理器列表 [AUTO-TRANSLATED:6dcfb11f]
|
||||
// Pull stream proxy list
|
||||
static ServiceController<PlayerProxy> s_player_proxy;
|
||||
|
||||
//推流代理器列表
|
||||
// 推流代理器列表 [AUTO-TRANSLATED:539a1bcf]
|
||||
// Push stream proxy list
|
||||
static ServiceController<PusherProxy> s_pusher_proxy;
|
||||
|
||||
//FFmpeg拉流代理器列表
|
||||
// FFmpeg拉流代理器列表 [AUTO-TRANSLATED:4bdedf10]
|
||||
// FFmpeg pull stream proxy list
|
||||
static ServiceController<FFmpegSource> s_ffmpeg_src;
|
||||
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
//rtp服务器列表
|
||||
// rtp服务器列表 [AUTO-TRANSLATED:2e362a8c]
|
||||
// RTP server list
|
||||
static ServiceController<RtpServer> s_rtp_server;
|
||||
#endif
|
||||
|
||||
@ -418,7 +430,8 @@ Value makeMediaSourceJson(MediaSource &media){
|
||||
item["originSock"] = Json::nullValue;
|
||||
}
|
||||
|
||||
//getLossRate有线程安全问题;使用getMediaInfo接口才能获取丢包率;getMediaList接口将忽略丢包率
|
||||
// getLossRate有线程安全问题;使用getMediaInfo接口才能获取丢包率;getMediaList接口将忽略丢包率 [AUTO-TRANSLATED:b2e927c6]
|
||||
// getLossRate has thread safety issues; use the getMediaInfo interface to get the packet loss rate; the getMediaList interface will ignore the packet loss rate
|
||||
auto current_thread = false;
|
||||
try { current_thread = media.getOwnerPoller()->isCurrentThread();} catch (...) {}
|
||||
float last_loss = -1;
|
||||
@ -430,7 +443,8 @@ Value makeMediaSourceJson(MediaSource &media){
|
||||
obj["ready"] = track->ready();
|
||||
obj["codec_type"] = codec_type;
|
||||
if (current_thread) {
|
||||
//rtp推流只有一个统计器,但是可能有多个track,如果短时间多次获取间隔丢包率,第二次会获取为-1
|
||||
// rtp推流只有一个统计器,但是可能有多个track,如果短时间多次获取间隔丢包率,第二次会获取为-1 [AUTO-TRANSLATED:5bfbc951]
|
||||
// RTP push stream has only one statistics, but may have multiple tracks. If you get the interval packet loss rate multiple times in a short time, the second time will get -1
|
||||
auto loss = media.getLossRate(codec_type);
|
||||
if (loss == -1) {
|
||||
loss = last_loss;
|
||||
@ -477,7 +491,8 @@ Value makeMediaSourceJson(MediaSource &media){
|
||||
uint16_t openRtpServer(uint16_t local_port, const mediakit::MediaTuple &tuple, int tcp_mode, const string &local_ip, bool re_use_port, uint32_t ssrc, int only_track, bool multiplex) {
|
||||
auto key = tuple.shortUrl();
|
||||
if (s_rtp_server.find(key)) {
|
||||
//为了防止RtpProcess所有权限混乱的问题,不允许重复添加相同的key
|
||||
// 为了防止RtpProcess所有权限混乱的问题,不允许重复添加相同的key [AUTO-TRANSLATED:06c7b14c]
|
||||
// To prevent the problem of all permissions being messed up in RtpProcess, duplicate keys are not allowed to be added
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -485,11 +500,13 @@ uint16_t openRtpServer(uint16_t local_port, const mediakit::MediaTuple &tuple, i
|
||||
server->start(local_port, local_ip.c_str(), tuple, (RtpServer::TcpMode)tcp_mode, re_use_port, ssrc, only_track, multiplex);
|
||||
});
|
||||
server->setOnDetach([key](const SockException &ex) {
|
||||
//设置rtp超时移除事件
|
||||
// 设置rtp超时移除事件 [AUTO-TRANSLATED:98d42cf3]
|
||||
// Set RTP timeout removal event
|
||||
s_rtp_server.erase(key);
|
||||
});
|
||||
|
||||
//回复json
|
||||
// 回复json [AUTO-TRANSLATED:0c443c6a]
|
||||
// Reply JSON
|
||||
return server->getPort();
|
||||
}
|
||||
|
||||
@ -543,7 +560,8 @@ void getStatisticJson(const function<void(Value &val)> &cb) {
|
||||
for (auto &val : *thread_mem_info) {
|
||||
(*obj)["threadMem"].append(val);
|
||||
}
|
||||
//触发回调
|
||||
// 触发回调 [AUTO-TRANSLATED:08ea452d]
|
||||
// Trigger callback
|
||||
cb(*obj);
|
||||
});
|
||||
|
||||
@ -584,27 +602,33 @@ void addStreamProxy(const MediaTuple &tuple, const string &url, int retry_count,
|
||||
const function<void(const SockException &ex, const string &key)> &cb) {
|
||||
auto key = tuple.shortUrl();
|
||||
if (s_player_proxy.find(key)) {
|
||||
//已经在拉流了
|
||||
// 已经在拉流了 [AUTO-TRANSLATED:e06c57d7]
|
||||
// Already pulling stream
|
||||
cb(SockException(Err_other, "This stream already exists"), key);
|
||||
return;
|
||||
}
|
||||
//添加拉流代理
|
||||
// 添加拉流代理 [AUTO-TRANSLATED:aa516f44]
|
||||
// Add pull stream proxy
|
||||
auto player = s_player_proxy.make(key, tuple, option, retry_count);
|
||||
|
||||
// 先透传拷贝参数
|
||||
// 先透传拷贝参数 [AUTO-TRANSLATED:22b5605e]
|
||||
// First pass-through copy parameters
|
||||
for (auto &pr : args) {
|
||||
(*player)[pr.first] = pr.second;
|
||||
}
|
||||
|
||||
//指定RTP over TCP(播放rtsp时有效)
|
||||
// 指定RTP over TCP(播放rtsp时有效) [AUTO-TRANSLATED:1a062656]
|
||||
// Specify RTP over TCP (effective when playing RTSP)
|
||||
(*player)[Client::kRtpType] = rtp_type;
|
||||
|
||||
if (timeout_sec > 0.1f) {
|
||||
//播放握手超时时间
|
||||
// 播放握手超时时间 [AUTO-TRANSLATED:5a29ae1f]
|
||||
// Play handshake timeout
|
||||
(*player)[Client::kTimeoutMS] = timeout_sec * 1000;
|
||||
}
|
||||
|
||||
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,默认一直重试
|
||||
// 开始播放,如果播放失败或者播放中止,将会自动重试若干次,默认一直重试 [AUTO-TRANSLATED:ac8499e5]
|
||||
// Start playing. If playback fails or is stopped, it will automatically retry several times, by default it will retry indefinitely
|
||||
player->setPlayCallbackOnce([cb, key](const SockException &ex) {
|
||||
if (ex) {
|
||||
s_player_proxy.erase(key);
|
||||
@ -612,7 +636,8 @@ void addStreamProxy(const MediaTuple &tuple, const string &url, int retry_count,
|
||||
cb(ex, key);
|
||||
});
|
||||
|
||||
//被主动关闭拉流
|
||||
// 被主动关闭拉流 [AUTO-TRANSLATED:41a19476]
|
||||
// The pull stream was actively closed
|
||||
player->setOnClose([key](const SockException &ex) {
|
||||
s_player_proxy.erase(key);
|
||||
});
|
||||
@ -636,23 +661,28 @@ void addStreamPusherProxy(const string &schema,
|
||||
return;
|
||||
}
|
||||
if (s_pusher_proxy.find(key)) {
|
||||
//已经在推流了
|
||||
// 已经在推流了 [AUTO-TRANSLATED:81fcd202]
|
||||
// Already pushing stream
|
||||
cb(SockException(Err_success), key);
|
||||
return;
|
||||
}
|
||||
|
||||
//添加推流代理
|
||||
// 添加推流代理 [AUTO-TRANSLATED:f9dbc76d]
|
||||
// Add push stream proxy
|
||||
auto pusher = s_pusher_proxy.make(key, src, retry_count);
|
||||
|
||||
//指定RTP over TCP(播放rtsp时有效)
|
||||
// 指定RTP over TCP(播放rtsp时有效) [AUTO-TRANSLATED:1a062656]
|
||||
// Specify RTP over TCP (effective when playing RTSP)
|
||||
pusher->emplace(Client::kRtpType, rtp_type);
|
||||
|
||||
if (timeout_sec > 0.1f) {
|
||||
//推流握手超时时间
|
||||
// 推流握手超时时间 [AUTO-TRANSLATED:00762fc1]
|
||||
// Push stream handshake timeout
|
||||
pusher->emplace(Client::kTimeoutMS, timeout_sec * 1000);
|
||||
}
|
||||
|
||||
//开始推流,如果推流失败或者推流中止,将会自动重试若干次,默认一直重试
|
||||
// 开始推流,如果推流失败或者推流中止,将会自动重试若干次,默认一直重试 [AUTO-TRANSLATED:c8b95088]
|
||||
// Start pushing stream. If the push stream fails or is stopped, it will automatically retry several times, by default it will retry indefinitely
|
||||
pusher->setPushCallbackOnce([cb, key, url](const SockException &ex) {
|
||||
if (ex) {
|
||||
WarnL << "Push " << url << " failed, key: " << key << ", err: " << ex;
|
||||
@ -661,7 +691,8 @@ void addStreamPusherProxy(const string &schema,
|
||||
cb(ex, key);
|
||||
});
|
||||
|
||||
//被主动关闭推流
|
||||
// 被主动关闭推流 [AUTO-TRANSLATED:bf216f82]
|
||||
// Stream closed actively
|
||||
pusher->setOnClose([key, url](const SockException &ex) {
|
||||
WarnL << "Push " << url << " failed, key: " << key << ", err: " << ex;
|
||||
s_pusher_proxy.erase(key);
|
||||
@ -674,13 +705,20 @@ void addStreamPusherProxy(const string &schema,
|
||||
* 安装api接口
|
||||
* 所有api都支持GET和POST两种方式
|
||||
* POST方式参数支持application/json和application/x-www-form-urlencoded方式
|
||||
* Install api interface
|
||||
* All apis support GET and POST methods
|
||||
* POST method parameters support application/json and application/x-www-form-urlencoded methods
|
||||
|
||||
* [AUTO-TRANSLATED:62e68c43]
|
||||
*/
|
||||
void installWebApi() {
|
||||
addHttpListener();
|
||||
GET_CONFIG(string,api_secret,API::kSecret);
|
||||
|
||||
//获取线程负载
|
||||
//测试url http://127.0.0.1/index/api/getThreadsLoad
|
||||
// 获取线程负载 [AUTO-TRANSLATED:3b0ece5c]
|
||||
// Get thread load
|
||||
// 测试url http://127.0.0.1/index/api/getThreadsLoad [AUTO-TRANSLATED:de1c93e7]
|
||||
// Test url http://127.0.0.1/index/api/getThreadsLoad
|
||||
api_regist("/index/api/getThreadsLoad", [](API_ARGS_MAP_ASYNC) {
|
||||
CHECK_SECRET();
|
||||
EventPollerPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
|
||||
@ -698,8 +736,10 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//获取后台工作线程负载
|
||||
//测试url http://127.0.0.1/index/api/getWorkThreadsLoad
|
||||
// 获取后台工作线程负载 [AUTO-TRANSLATED:6166e265]
|
||||
// Get background worker thread load
|
||||
// 测试url http://127.0.0.1/index/api/getWorkThreadsLoad [AUTO-TRANSLATED:209a8bc1]
|
||||
// Test url http://127.0.0.1/index/api/getWorkThreadsLoad
|
||||
api_regist("/index/api/getWorkThreadsLoad", [](API_ARGS_MAP_ASYNC) {
|
||||
CHECK_SECRET();
|
||||
WorkThreadPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
|
||||
@ -717,8 +757,10 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//获取服务器配置
|
||||
//测试url http://127.0.0.1/index/api/getServerConfig
|
||||
// 获取服务器配置 [AUTO-TRANSLATED:7dd2f3da]
|
||||
// Get server configuration
|
||||
// 测试url http://127.0.0.1/index/api/getServerConfig [AUTO-TRANSLATED:59cd0d71]
|
||||
// Test url http://127.0.0.1/index/api/getServerConfig
|
||||
api_regist("/index/api/getServerConfig",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
Value obj;
|
||||
@ -728,9 +770,12 @@ void installWebApi() {
|
||||
val["data"].append(obj);
|
||||
});
|
||||
|
||||
//设置服务器配置
|
||||
//测试url(比如关闭http api调试) http://127.0.0.1/index/api/setServerConfig?api.apiDebug=0
|
||||
//你也可以通过http post方式传参,可以通过application/x-www-form-urlencoded或application/json方式传参
|
||||
// 设置服务器配置 [AUTO-TRANSLATED:3de7bd37]
|
||||
// Set server configuration
|
||||
// 测试url(比如关闭http api调试) http://127.0.0.1/index/api/setServerConfig?api.apiDebug=0 [AUTO-TRANSLATED:9471d218]
|
||||
// Test url (e.g. disable http api debugging) http://127.0.0.1/index/api/setServerConfig?api.apiDebug=0
|
||||
// 你也可以通过http post方式传参,可以通过application/x-www-form-urlencoded或application/json方式传参 [AUTO-TRANSLATED:d493a7c0]
|
||||
// You can also pass parameters through http post method, you can pass parameters through application/x-www-form-urlencoded or application/json methods
|
||||
api_regist("/index/api/setServerConfig",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
auto &ini = mINI::Instance();
|
||||
@ -738,12 +783,15 @@ void installWebApi() {
|
||||
for (auto &pr : allArgs.args) {
|
||||
if (ini.find(pr.first) == ini.end()) {
|
||||
#if 1
|
||||
//没有这个key
|
||||
// 没有这个key [AUTO-TRANSLATED:d6855e02]
|
||||
// This key does not exist
|
||||
continue;
|
||||
#else
|
||||
// 新增配置选项,为了动态添加多个ffmpeg cmd 模板
|
||||
// 新增配置选项,为了动态添加多个ffmpeg cmd 模板 [AUTO-TRANSLATED:0f977fcd]
|
||||
// Add configuration options to dynamically add multiple ffmpeg cmd templates
|
||||
ini[pr.first] = pr.second;
|
||||
// 防止changed变化
|
||||
// 防止changed变化 [AUTO-TRANSLATED:f8ad7e59]
|
||||
// Prevent changed changes
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
@ -755,7 +803,8 @@ void installWebApi() {
|
||||
continue;
|
||||
}
|
||||
ini[pr.first] = pr.second;
|
||||
//替换成功
|
||||
// 替换成功 [AUTO-TRANSLATED:b5d4fec1]
|
||||
// Replacement successful
|
||||
++changed;
|
||||
}
|
||||
if (changed > 0) {
|
||||
@ -773,28 +822,36 @@ void installWebApi() {
|
||||
}
|
||||
};
|
||||
|
||||
//获取服务器api列表
|
||||
//测试url http://127.0.0.1/index/api/getApiList
|
||||
// 获取服务器api列表 [AUTO-TRANSLATED:e4c0dd9d]
|
||||
// Get server api list
|
||||
// 测试url http://127.0.0.1/index/api/getApiList [AUTO-TRANSLATED:df09e368]
|
||||
// Test url http://127.0.0.1/index/api/getApiList
|
||||
api_regist("/index/api/getApiList",[](API_ARGS_MAP){
|
||||
s_get_api_list(API_ARGS_VALUE);
|
||||
});
|
||||
|
||||
//获取服务器api列表
|
||||
//测试url http://127.0.0.1/index/
|
||||
// 获取服务器api列表 [AUTO-TRANSLATED:e4c0dd9d]
|
||||
// Get server api list
|
||||
// 测试url http://127.0.0.1/index/ [AUTO-TRANSLATED:76934dd3]
|
||||
// Test url http://127.0.0.1/index/
|
||||
api_regist("/index/",[](API_ARGS_MAP){
|
||||
s_get_api_list(API_ARGS_VALUE);
|
||||
});
|
||||
|
||||
#if !defined(_WIN32)
|
||||
//重启服务器,只有Daemon方式才能重启,否则是直接关闭!
|
||||
//测试url http://127.0.0.1/index/api/restartServer
|
||||
// 重启服务器,只有Daemon方式才能重启,否则是直接关闭! [AUTO-TRANSLATED:9d8a1c32]
|
||||
// Restart server, only Daemon mode can restart, otherwise it will be closed directly!
|
||||
// 测试url http://127.0.0.1/index/api/restartServer [AUTO-TRANSLATED:8beaaa8a]
|
||||
// Test url http://127.0.0.1/index/api/restartServer
|
||||
api_regist("/index/api/restartServer",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
EventPollerPool::Instance().getPoller()->doDelayTask(1000,[](){
|
||||
//尝试正常退出
|
||||
// 尝试正常退出 [AUTO-TRANSLATED:93828d0f]
|
||||
// Try to exit normally
|
||||
::kill(getpid(), SIGINT);
|
||||
|
||||
//3秒后强制退出
|
||||
// 3秒后强制退出 [AUTO-TRANSLATED:fdc82920]
|
||||
// Force exit after 3 seconds
|
||||
EventPollerPool::Instance().getPoller()->doDelayTask(3000,[](){
|
||||
exit(0);
|
||||
return 0;
|
||||
@ -805,10 +862,12 @@ void installWebApi() {
|
||||
val["msg"] = "MediaServer will reboot in on 1 second";
|
||||
});
|
||||
#else
|
||||
//增加Windows下的重启代码
|
||||
// 增加Windows下的重启代码 [AUTO-TRANSLATED:dcba12d5]
|
||||
// Add restart code for Windows
|
||||
api_regist("/index/api/restartServer", [](API_ARGS_MAP) {
|
||||
CHECK_SECRET();
|
||||
//创建重启批处理脚本文件
|
||||
// 创建重启批处理脚本文件 [AUTO-TRANSLATED:cc18c259]
|
||||
// Create a restart batch script file
|
||||
FILE *pf;
|
||||
errno_t err = ::_wfopen_s(&pf, L"RestartServer.cmd", L"w"); //“w”如果该文件存在,其内容将被覆盖
|
||||
if (err == 0) {
|
||||
@ -824,7 +883,8 @@ void installWebApi() {
|
||||
strcat(exeName, ext);
|
||||
fprintf(pf, "@echo off\ntaskkill /f /im %s\nstart \"\" \"%s\"\ndel %%0", exeName, szExeName);
|
||||
fclose(pf);
|
||||
// 1秒后执行创建的批处理脚本
|
||||
// 1秒后执行创建的批处理脚本 [AUTO-TRANSLATED:596dbca9]
|
||||
// Execute the created batch script after 1 second
|
||||
EventPollerPool::Instance().getPoller()->doDelayTask(1000, []() {
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
@ -859,27 +919,35 @@ void installWebApi() {
|
||||
});
|
||||
#endif//#if !defined(_WIN32)
|
||||
|
||||
//获取流列表,可选筛选参数
|
||||
//测试url0(获取所有流) http://127.0.0.1/index/api/getMediaList
|
||||
//测试url1(获取虚拟主机为"__defaultVost__"的流) http://127.0.0.1/index/api/getMediaList?vhost=__defaultVost__
|
||||
//测试url2(获取rtsp类型的流) http://127.0.0.1/index/api/getMediaList?schema=rtsp
|
||||
// 获取流列表,可选筛选参数 [AUTO-TRANSLATED:68ffc6b6]
|
||||
// Get stream list, optional filtering parameters
|
||||
// 测试url0(获取所有流) http://127.0.0.1/index/api/getMediaList [AUTO-TRANSLATED:434652ea]
|
||||
// Test url0 (get all streams) http://127.0.0.1/index/api/getMediaList
|
||||
// 测试url1(获取虚拟主机为"__defaultVost__"的流) http://127.0.0.1/index/api/getMediaList?vhost=__defaultVost__ [AUTO-TRANSLATED:5d9bd1ee]
|
||||
// Test url1 (get streams with virtual host "__defaultVost__") http://127.0.0.1/index/api/getMediaList?vhost=__defaultVost__
|
||||
// 测试url2(获取rtsp类型的流) http://127.0.0.1/index/api/getMediaList?schema=rtsp [AUTO-TRANSLATED:21c2c15d]
|
||||
// Test url2 (get rtsp type streams) http://127.0.0.1/index/api/getMediaList?schema=rtsp
|
||||
api_regist("/index/api/getMediaList",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
//获取所有MediaSource列表
|
||||
// 获取所有MediaSource列表 [AUTO-TRANSLATED:7bf16dc2]
|
||||
// Get all MediaSource lists
|
||||
MediaSource::for_each_media([&](const MediaSource::Ptr &media) {
|
||||
val["data"].append(makeMediaSourceJson(*media));
|
||||
}, allArgs["schema"], allArgs["vhost"], allArgs["app"], allArgs["stream"]);
|
||||
});
|
||||
|
||||
//测试url http://127.0.0.1/index/api/isMediaOnline?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
// 测试url http://127.0.0.1/index/api/isMediaOnline?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs [AUTO-TRANSLATED:126a75e8]
|
||||
// Test url http://127.0.0.1/index/api/isMediaOnline?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
api_regist("/index/api/isMediaOnline",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema","vhost","app","stream");
|
||||
val["online"] = (bool) (MediaSource::find(allArgs["schema"],allArgs["vhost"],allArgs["app"],allArgs["stream"]));
|
||||
});
|
||||
|
||||
//获取媒体流播放器列表
|
||||
//测试url http://127.0.0.1/index/api/getMediaPlayerList?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
// 获取媒体流播放器列表 [AUTO-TRANSLATED:bcadf31c]
|
||||
// Get media stream player list
|
||||
// 测试url http://127.0.0.1/index/api/getMediaPlayerList?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs [AUTO-TRANSLATED:2aab7522]
|
||||
// Test url http://127.0.0.1/index/api/getMediaPlayerList?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
api_regist("/index/api/getMediaPlayerList",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema", "vhost", "app", "stream");
|
||||
@ -922,7 +990,8 @@ void installWebApi() {
|
||||
src->broadcastMessage(any);
|
||||
});
|
||||
|
||||
//测试url http://127.0.0.1/index/api/getMediaInfo?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
// 测试url http://127.0.0.1/index/api/getMediaInfo?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs [AUTO-TRANSLATED:9402e811]
|
||||
// Test url http://127.0.0.1/index/api/getMediaInfo?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs
|
||||
api_regist("/index/api/getMediaInfo",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema","vhost","app","stream");
|
||||
@ -937,12 +1006,15 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//主动关断流,包括关断拉流、推流
|
||||
//测试url http://127.0.0.1/index/api/close_stream?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1
|
||||
// 主动关断流,包括关断拉流、推流 [AUTO-TRANSLATED:80506955]
|
||||
// Actively close the stream, including closing the pull stream and push stream
|
||||
// 测试url http://127.0.0.1/index/api/close_stream?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1 [AUTO-TRANSLATED:c3831592]
|
||||
// Test url http://127.0.0.1/index/api/close_stream?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1
|
||||
api_regist("/index/api/close_stream",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema","vhost","app","stream");
|
||||
//踢掉推流器
|
||||
// 踢掉推流器 [AUTO-TRANSLATED:61e39b14]
|
||||
// Kick out the pusher
|
||||
auto src = MediaSource::find(allArgs["schema"],
|
||||
allArgs["vhost"],
|
||||
allArgs["app"],
|
||||
@ -961,11 +1033,14 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//批量主动关断流,包括关断拉流、推流
|
||||
//测试url http://127.0.0.1/index/api/close_streams?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1
|
||||
// 批量主动关断流,包括关断拉流、推流 [AUTO-TRANSLATED:5d180cd8]
|
||||
// Batch actively close the stream, including closing the pull stream and push stream
|
||||
// 测试url http://127.0.0.1/index/api/close_streams?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1 [AUTO-TRANSLATED:786933db]
|
||||
// Test url http://127.0.0.1/index/api/close_streams?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1
|
||||
api_regist("/index/api/close_streams",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
//筛选命中个数
|
||||
// 筛选命中个数 [AUTO-TRANSLATED:6db1e8c7]
|
||||
// Filter hit count
|
||||
int count_hit = 0;
|
||||
int count_closed = 0;
|
||||
list<MediaSource::Ptr> media_list;
|
||||
@ -984,9 +1059,12 @@ void installWebApi() {
|
||||
val["count_closed"] = count_closed;
|
||||
});
|
||||
|
||||
//获取所有Session列表信息
|
||||
//可以根据本地端口和远端ip来筛选
|
||||
//测试url(筛选某端口下的tcp会话) http://127.0.0.1/index/api/getAllSession?local_port=1935
|
||||
// 获取所有Session列表信息 [AUTO-TRANSLATED:e785052d]
|
||||
// Get all Session list information
|
||||
// 可以根据本地端口和远端ip来筛选 [AUTO-TRANSLATED:4d4c9d61]
|
||||
// You can filter by local port and remote ip
|
||||
// 测试url(筛选某端口下的tcp会话) http://127.0.0.1/index/api/getAllSession?local_port=1935 [AUTO-TRANSLATED:ef845193]
|
||||
// Test url (filter tcp session under a certain port) http://127.0.0.1/index/api/getAllSession?local_port=1935
|
||||
api_regist("/index/api/getAllSession",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
Value jsession;
|
||||
@ -1007,12 +1085,15 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//断开tcp连接,比如说可以断开rtsp、rtmp播放器等
|
||||
//测试url http://127.0.0.1/index/api/kick_session?id=123456
|
||||
// 断开tcp连接,比如说可以断开rtsp、rtmp播放器等 [AUTO-TRANSLATED:9147ffec]
|
||||
// Disconnect the tcp connection, for example, you can disconnect the rtsp, rtmp player, etc.
|
||||
// 测试url http://127.0.0.1/index/api/kick_session?id=123456 [AUTO-TRANSLATED:c2880cb5]
|
||||
// Test url http://127.0.0.1/index/api/kick_session?id=123456
|
||||
api_regist("/index/api/kick_session",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("id");
|
||||
//踢掉tcp会话
|
||||
// 踢掉tcp会话 [AUTO-TRANSLATED:f6f318bd]
|
||||
// Kick out the tcp session
|
||||
auto session = SessionMap::Instance().get(allArgs["id"]);
|
||||
if(!session){
|
||||
throw ApiRetException("can not find the target",API::OtherFailed);
|
||||
@ -1021,8 +1102,10 @@ void installWebApi() {
|
||||
});
|
||||
|
||||
|
||||
//批量断开tcp连接,比如说可以断开rtsp、rtmp播放器等
|
||||
//测试url http://127.0.0.1/index/api/kick_sessions?local_port=1935
|
||||
// 批量断开tcp连接,比如说可以断开rtsp、rtmp播放器等 [AUTO-TRANSLATED:fef59eb8]
|
||||
// Batch disconnect tcp connections, for example, you can disconnect rtsp, rtmp players, etc.
|
||||
// 测试url http://127.0.0.1/index/api/kick_sessions?local_port=1935 [AUTO-TRANSLATED:5891b482]
|
||||
// Test url http://127.0.0.1/index/api/kick_sessions?local_port=1935
|
||||
api_regist("/index/api/kick_sessions", [](API_ARGS_MAP) {
|
||||
CHECK_SECRET();
|
||||
uint16_t local_port = allArgs["local_port"].as<uint16_t>();
|
||||
@ -1038,7 +1121,8 @@ void installWebApi() {
|
||||
return;
|
||||
}
|
||||
if (session->getIdentifier() == sender.getIdentifier()) {
|
||||
// 忽略本http链接
|
||||
// 忽略本http链接 [AUTO-TRANSLATED:9fb4bf76]
|
||||
// Ignore this http link
|
||||
return;
|
||||
}
|
||||
session_list.emplace_back(session);
|
||||
@ -1051,8 +1135,10 @@ void installWebApi() {
|
||||
val["count_hit"] = (Json::UInt64)count_hit;
|
||||
});
|
||||
|
||||
//动态添加rtsp/rtmp推流代理
|
||||
//测试url http://127.0.0.1/index/api/addStreamPusherProxy?schema=rtmp&vhost=__defaultVhost__&app=proxy&stream=0&dst_url=rtmp://127.0.0.1/live/obs
|
||||
// 动态添加rtsp/rtmp推流代理 [AUTO-TRANSLATED:2eb09bc9]
|
||||
// Dynamically add rtsp/rtmp push stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/addStreamPusherProxy?schema=rtmp&vhost=__defaultVhost__&app=proxy&stream=0&dst_url=rtmp://127.0.0.1/live/obs [AUTO-TRANSLATED:25d7d4b0]
|
||||
// Test url http://127.0.0.1/index/api/addStreamPusherProxy?schema=rtmp&vhost=__defaultVhost__&app=proxy&stream=0&dst_url=rtmp://127.0.0.1/live/obs
|
||||
api_regist("/index/api/addStreamPusherProxy", [](API_ARGS_MAP_ASYNC) {
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema", "vhost", "app", "stream", "dst_url");
|
||||
@ -1078,16 +1164,20 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//关闭推流代理
|
||||
//测试url http://127.0.0.1/index/api/delStreamPusherProxy?key=__defaultVhost__/proxy/0
|
||||
// 关闭推流代理 [AUTO-TRANSLATED:91602b75]
|
||||
// Close the push stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/delStreamPusherProxy?key=__defaultVhost__/proxy/0 [AUTO-TRANSLATED:2671206c]
|
||||
// Test url http://127.0.0.1/index/api/delStreamPusherProxy?key=__defaultVhost__/proxy/0
|
||||
api_regist("/index/api/delStreamPusherProxy", [](API_ARGS_MAP) {
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("key");
|
||||
val["data"]["flag"] = s_pusher_proxy.erase(allArgs["key"]) == 1;
|
||||
});
|
||||
|
||||
//动态添加rtsp/rtmp拉流代理
|
||||
//测试url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs
|
||||
// 动态添加rtsp/rtmp拉流代理 [AUTO-TRANSLATED:2616537c]
|
||||
// Dynamically add rtsp/rtmp pull stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs [AUTO-TRANSLATED:71ddce15]
|
||||
// Test url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs
|
||||
api_regist("/index/api/addStreamProxy",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("vhost","app","stream","url");
|
||||
@ -1123,8 +1213,10 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//关闭拉流代理
|
||||
//测试url http://127.0.0.1/index/api/delStreamProxy?key=__defaultVhost__/proxy/0
|
||||
// 关闭拉流代理 [AUTO-TRANSLATED:5204f128]
|
||||
// Close the pull stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/delStreamProxy?key=__defaultVhost__/proxy/0 [AUTO-TRANSLATED:2b0903ef]
|
||||
// Test url http://127.0.0.1/index/api/delStreamProxy?key=__defaultVhost__/proxy/0
|
||||
api_regist("/index/api/delStreamProxy",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("key");
|
||||
@ -1140,7 +1232,8 @@ void installWebApi() {
|
||||
const function<void(const SockException &ex, const string &key)> &cb) {
|
||||
auto key = MD5(dst_url).hexdigest();
|
||||
if (s_ffmpeg_src.find(key)) {
|
||||
//已经在拉流了
|
||||
// 已经在拉流了 [AUTO-TRANSLATED:e06c57d7]
|
||||
// Already pulling
|
||||
cb(SockException(Err_success), key);
|
||||
return;
|
||||
}
|
||||
@ -1159,8 +1252,10 @@ void installWebApi() {
|
||||
});
|
||||
};
|
||||
|
||||
//动态添加rtsp/rtmp拉流代理
|
||||
//测试url http://127.0.0.1/index/api/addFFmpegSource?src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000
|
||||
// 动态添加rtsp/rtmp拉流代理 [AUTO-TRANSLATED:2616537c]
|
||||
// Dynamically add rtsp/rtmp pull stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/addFFmpegSource?src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000 [AUTO-TRANSLATED:501cdd89]
|
||||
// // Test url http://127.0.0.1/index/api/addFFmpegSource?src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000
|
||||
api_regist("/index/api/addFFmpegSource",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("src_url","dst_url","timeout_ms");
|
||||
@ -1182,16 +1277,20 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//关闭拉流代理
|
||||
//测试url http://127.0.0.1/index/api/delFFmepgSource?key=key
|
||||
// 关闭拉流代理 [AUTO-TRANSLATED:5204f128]
|
||||
// Close the pull stream proxy
|
||||
// 测试url http://127.0.0.1/index/api/delFFmepgSource?key=key [AUTO-TRANSLATED:ed6fa147]
|
||||
// Test url http://127.0.0.1/index/api/delFFmepgSource?key=key
|
||||
api_regist("/index/api/delFFmpegSource",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("key");
|
||||
val["data"]["flag"] = s_ffmpeg_src.erase(allArgs["key"]) == 1;
|
||||
});
|
||||
|
||||
//新增http api下载可执行程序文件接口
|
||||
//测试url http://127.0.0.1/index/api/downloadBin
|
||||
// 新增http api下载可执行程序文件接口 [AUTO-TRANSLATED:d6e44e84]
|
||||
// Add a new http api to download executable files
|
||||
// 测试url http://127.0.0.1/index/api/downloadBin [AUTO-TRANSLATED:9525e834]
|
||||
// Test url http://127.0.0.1/index/api/downloadBin
|
||||
api_regist("/index/api/downloadBin",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
invoker.responseFile(allArgs.parser.getHeader(), StrCaseMap(), exePath());
|
||||
@ -1234,12 +1333,14 @@ void installWebApi() {
|
||||
auto tuple = MediaTuple { vhost, app, stream_id, "" };
|
||||
auto tcp_mode = allArgs["tcp_mode"].as<int>();
|
||||
if (allArgs["enable_tcp"].as<int>() && !tcp_mode) {
|
||||
//兼容老版本请求,新版本去除enable_tcp参数并新增tcp_mode参数
|
||||
// 兼容老版本请求,新版本去除enable_tcp参数并新增tcp_mode参数 [AUTO-TRANSLATED:3b6a5ab5]
|
||||
// Compatible with old version requests, the new version removes the enable_tcp parameter and adds the tcp_mode parameter
|
||||
tcp_mode = 1;
|
||||
}
|
||||
auto only_track = allArgs["only_track"].as<int>();
|
||||
if (allArgs["only_audio"].as<bool>()) {
|
||||
// 兼容老版本请求,新版本去除only_audio参数并新增only_track参数
|
||||
// 兼容老版本请求,新版本去除only_audio参数并新增only_track参数 [AUTO-TRANSLATED:a7a40942]
|
||||
// Compatible with old version requests, the new version removes the only_audio parameter and adds the only_track parameter
|
||||
only_track = 1;
|
||||
}
|
||||
GET_CONFIG(std::string, local_ip, General::kListenIP)
|
||||
@ -1251,7 +1352,8 @@ void installWebApi() {
|
||||
if (port == 0) {
|
||||
throw InvalidArgsException("This stream already exists");
|
||||
}
|
||||
//回复json
|
||||
// 回复json [AUTO-TRANSLATED:0c443c6a]
|
||||
// Reply json
|
||||
val["port"] = port;
|
||||
});
|
||||
|
||||
@ -1270,12 +1372,14 @@ void installWebApi() {
|
||||
auto tuple = MediaTuple { vhost, app, stream_id, "" };
|
||||
auto tcp_mode = allArgs["tcp_mode"].as<int>();
|
||||
if (allArgs["enable_tcp"].as<int>() && !tcp_mode) {
|
||||
// 兼容老版本请求,新版本去除enable_tcp参数并新增tcp_mode参数
|
||||
// 兼容老版本请求,新版本去除enable_tcp参数并新增tcp_mode参数 [AUTO-TRANSLATED:b5f8f5df]
|
||||
// Compatible with old version requests, the new version removes the enable_tcp parameter and adds the tcp_mode parameter
|
||||
tcp_mode = 1;
|
||||
}
|
||||
auto only_track = allArgs["only_track"].as<int>();
|
||||
if (allArgs["only_audio"].as<bool>()) {
|
||||
// 兼容老版本请求,新版本去除only_audio参数并新增only_track参数
|
||||
// 兼容老版本请求,新版本去除only_audio参数并新增only_track参数 [AUTO-TRANSLATED:a7a40942]
|
||||
// Compatible with old version requests, the new version removes the only_audio parameter and adds the only_track parameter
|
||||
only_track = 1;
|
||||
}
|
||||
std::string local_ip = "::";
|
||||
@ -1287,7 +1391,8 @@ void installWebApi() {
|
||||
if (port == 0) {
|
||||
throw InvalidArgsException("This stream already exists");
|
||||
}
|
||||
// 回复json
|
||||
// 回复json [AUTO-TRANSLATED:e80815cd]
|
||||
// Reply json
|
||||
val["port"] = port;
|
||||
});
|
||||
|
||||
@ -1384,7 +1489,8 @@ void installWebApi() {
|
||||
}
|
||||
auto type = allArgs["type"].empty() ? (int)MediaSourceEvent::SendRtpArgs::kRtpPS : allArgs["type"].as<int>();
|
||||
if (!allArgs["use_ps"].empty()) {
|
||||
// 兼容之前的use_ps参数
|
||||
// 兼容之前的use_ps参数 [AUTO-TRANSLATED:0193f489]
|
||||
// Compatible with the previous use_ps parameter
|
||||
type = allArgs["use_ps"].as<int>();
|
||||
}
|
||||
MediaSourceEvent::SendRtpArgs args;
|
||||
@ -1404,7 +1510,8 @@ void installWebApi() {
|
||||
args.udp_rtcp_timeout = allArgs["udp_rtcp_timeout"];
|
||||
args.recv_stream_id = allArgs["recv_stream_id"];
|
||||
args.close_delay_ms = allArgs["close_delay_ms"];
|
||||
// 记录发送流的app和vhost
|
||||
// 记录发送流的app和vhost [AUTO-TRANSLATED:ee1b41d5]
|
||||
// Record the app and vhost of the sending stream
|
||||
args.recv_stream_app = allArgs["app"];
|
||||
args.recv_stream_vhost = allArgs["vhost"];
|
||||
src->getOwnerPoller()->async([=]() mutable {
|
||||
@ -1467,7 +1574,8 @@ void installWebApi() {
|
||||
}
|
||||
|
||||
src->getOwnerPoller()->async([=]() mutable {
|
||||
// ssrc如果为空,关闭全部
|
||||
// ssrc如果为空,关闭全部 [AUTO-TRANSLATED:e0955dab]
|
||||
// If ssrc is empty, close all
|
||||
if (!src->stopSendRtp(allArgs["ssrc"])) {
|
||||
val["code"] = API::OtherFailed;
|
||||
val["msg"] = "stopSendRtp failed";
|
||||
@ -1489,7 +1597,8 @@ void installWebApi() {
|
||||
if (!allArgs["app"].empty()) {
|
||||
app = allArgs["app"];
|
||||
}
|
||||
//只是暂停流的检查,流媒体服务器做为流负载服务,收流就转发,RTSP/RTMP有自己暂停协议
|
||||
// 只是暂停流的检查,流媒体服务器做为流负载服务,收流就转发,RTSP/RTMP有自己暂停协议 [AUTO-TRANSLATED:dda6ee31]
|
||||
// Only pause the stream check, the media server acts as a stream load balancing service, receiving the stream and forwarding it, RTSP/RTMP has its own pause protocol
|
||||
auto src = MediaSource::find(vhost, app, allArgs["stream_id"]);
|
||||
auto process = src ? src->getRtpProcess() : nullptr;
|
||||
if (process) {
|
||||
@ -1521,7 +1630,8 @@ void installWebApi() {
|
||||
|
||||
#endif//ENABLE_RTPPROXY
|
||||
|
||||
// 开始录制hls或MP4
|
||||
// 开始录制hls或MP4 [AUTO-TRANSLATED:0818775e]
|
||||
// Start recording hls or MP4
|
||||
api_regist("/index/api/startRecord",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("type","vhost","app","stream");
|
||||
@ -1540,7 +1650,8 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
//设置录像流播放速度
|
||||
// 设置录像流播放速度 [AUTO-TRANSLATED:a8d82298]
|
||||
// Set the playback speed of the recording stream
|
||||
api_regist("/index/api/setRecordSpeed", [](API_ARGS_MAP_ASYNC) {
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("schema", "vhost", "app", "stream", "speed");
|
||||
@ -1583,7 +1694,8 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
// 停止录制hls或MP4
|
||||
// 停止录制hls或MP4 [AUTO-TRANSLATED:24d11a0c]
|
||||
// Stop recording hls or MP4
|
||||
api_regist("/index/api/stopRecord",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("type","vhost","app","stream");
|
||||
@ -1603,7 +1715,8 @@ void installWebApi() {
|
||||
});
|
||||
});
|
||||
|
||||
// 获取hls或MP4录制状态
|
||||
// 获取hls或MP4录制状态 [AUTO-TRANSLATED:a08a2f1a]
|
||||
// Get the recording status of hls or MP4
|
||||
api_regist("/index/api/isRecording",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("type","vhost","app","stream");
|
||||
@ -1648,7 +1761,8 @@ void installWebApi() {
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
});
|
||||
|
||||
// 删除录像文件夹
|
||||
// 删除录像文件夹 [AUTO-TRANSLATED:821aed07]
|
||||
// Delete the recording folder
|
||||
// http://127.0.0.1/index/api/deleteRecordDirectroy?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01-01
|
||||
api_regist("/index/api/deleteRecordDirectory", [](API_ARGS_MAP) {
|
||||
CHECK_SECRET();
|
||||
@ -1661,10 +1775,12 @@ void installWebApi() {
|
||||
bool recording = false;
|
||||
auto name = allArgs["name"];
|
||||
if (!name.empty()) {
|
||||
// 删除指定文件
|
||||
// 删除指定文件 [AUTO-TRANSLATED:e8ee7bfa]
|
||||
// Delete the specified file
|
||||
record_path += name;
|
||||
} else {
|
||||
// 删除文件夹,先判断该流是否正在录制中
|
||||
// 删除文件夹,先判断该流是否正在录制中 [AUTO-TRANSLATED:9f124786]
|
||||
// Delete the folder, first check if the stream is being recorded
|
||||
auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]);
|
||||
if (src && src->isRecording(Recorder::type_mp4)) {
|
||||
recording = true;
|
||||
@ -1689,7 +1805,8 @@ void installWebApi() {
|
||||
File::deleteEmptyDir(record_path);
|
||||
});
|
||||
|
||||
//获取录像文件夹列表或mp4文件列表
|
||||
// 获取录像文件夹列表或mp4文件列表 [AUTO-TRANSLATED:f7e299bc]
|
||||
// Get the list of recording folders or mp4 files
|
||||
//http://127.0.0.1/index/api/getMP4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01
|
||||
api_regist("/index/api/getMP4RecordFile", [](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
@ -1698,25 +1815,29 @@ void installWebApi() {
|
||||
auto record_path = Recorder::getRecordPath(Recorder::type_mp4, tuple, allArgs["customized_path"]);
|
||||
auto period = allArgs["period"];
|
||||
|
||||
//判断是获取mp4文件列表还是获取文件夹列表
|
||||
// 判断是获取mp4文件列表还是获取文件夹列表 [AUTO-TRANSLATED:b9c86d2f]
|
||||
// Determine whether to get the mp4 file list or the folder list
|
||||
bool search_mp4 = period.size() == sizeof("2020-02-01") - 1;
|
||||
if (search_mp4) {
|
||||
record_path = record_path + period + "/";
|
||||
}
|
||||
|
||||
Json::Value paths(arrayValue);
|
||||
//这是筛选日期,获取文件夹列表
|
||||
// 这是筛选日期,获取文件夹列表 [AUTO-TRANSLATED:786fa49d]
|
||||
// This is to filter the date and get the folder list
|
||||
File::scanDir(record_path, [&](const string &path, bool isDir) {
|
||||
auto pos = path.rfind('/');
|
||||
if (pos != string::npos) {
|
||||
string relative_path = path.substr(pos + 1);
|
||||
if (search_mp4) {
|
||||
if (!isDir) {
|
||||
//我们只收集mp4文件,对文件夹不感兴趣
|
||||
// 我们只收集mp4文件,对文件夹不感兴趣 [AUTO-TRANSLATED:254d9f25]
|
||||
// We only collect mp4 files, we are not interested in folders
|
||||
paths.append(relative_path);
|
||||
}
|
||||
} else if (isDir && relative_path.find(period) == 0) {
|
||||
//匹配到对应日期的文件夹
|
||||
// 匹配到对应日期的文件夹 [AUTO-TRANSLATED:cd3d10b9]
|
||||
// Match the folder for the corresponding date
|
||||
paths.append(relative_path);
|
||||
}
|
||||
}
|
||||
@ -1736,24 +1857,29 @@ void installWebApi() {
|
||||
GET_CONFIG(string, defaultSnap, API::kDefaultSnap);
|
||||
if (!File::fileSize(snap_path)) {
|
||||
if (!err_msg.empty() && (!s_snap_success_once || defaultSnap.empty())) {
|
||||
//重来没截图成功过或者默认截图图片为空,那么直接返回FFmpeg错误日志
|
||||
// 重来没截图成功过或者默认截图图片为空,那么直接返回FFmpeg错误日志 [AUTO-TRANSLATED:5bde510f]
|
||||
// If the screenshot has never been successful or the default screenshot image is empty, then directly return the FFmpeg error log
|
||||
headerOut["Content-Type"] = HttpFileManager::getContentType(".txt");
|
||||
invoker.responseFile(headerIn, headerOut, err_msg, false, false);
|
||||
return;
|
||||
}
|
||||
//截图成功过一次,那么认为配置无错误,截图失败时,返回预设默认图片
|
||||
// 截图成功过一次,那么认为配置无错误,截图失败时,返回预设默认图片 [AUTO-TRANSLATED:ffe4d807]
|
||||
// If the screenshot has been successful once, then it is considered that the configuration is error-free, and when the screenshot fails, the preset default image is returned
|
||||
const_cast<string &>(snap_path) = File::absolutePath("", defaultSnap);
|
||||
headerOut["Content-Type"] = HttpFileManager::getContentType(snap_path.data());
|
||||
} else {
|
||||
s_snap_success_once = true;
|
||||
//之前生成的截图文件,我们默认为jpeg格式
|
||||
// 之前生成的截图文件,我们默认为jpeg格式 [AUTO-TRANSLATED:5cc5c1ff]
|
||||
// The previously generated screenshot file, we default to jpeg format
|
||||
headerOut["Content-Type"] = HttpFileManager::getContentType(".jpeg");
|
||||
}
|
||||
//返回图片给http客户端
|
||||
// 返回图片给http客户端 [AUTO-TRANSLATED:58a1f64e]
|
||||
// Return image to http client
|
||||
invoker.responseFile(headerIn, headerOut, snap_path);
|
||||
};
|
||||
|
||||
//获取截图缓存或者实时截图
|
||||
// 获取截图缓存或者实时截图 [AUTO-TRANSLATED:78e2fe1e]
|
||||
// Get screenshot cache or real-time screenshot
|
||||
//http://127.0.0.1/index/api/getSnap?url=rtmp://127.0.0.1/record/robot.mp4&timeout_sec=10&expire_sec=3
|
||||
api_regist("/index/api/getSnap", [](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
@ -1767,49 +1893,61 @@ void installWebApi() {
|
||||
|
||||
File::scanDir(scan_path, [&](const string &path, bool isDir) {
|
||||
if (isDir || !end_with(path, ".jpeg")) {
|
||||
//忽略文件夹或其他类型的文件
|
||||
// 忽略文件夹或其他类型的文件 [AUTO-TRANSLATED:3ecffcae]
|
||||
// Ignore folders or other types of files
|
||||
return true;
|
||||
}
|
||||
|
||||
//找到截图
|
||||
// 找到截图 [AUTO-TRANSLATED:b784cfec]
|
||||
// Find screenshot
|
||||
auto tm = findSubString(path.data() + scan_path.size(), nullptr, ".jpeg");
|
||||
if (atoll(tm.data()) + expire_sec < time(NULL)) {
|
||||
//截图已经过期,改名,以便再次请求时,可以返回老截图
|
||||
// 截图已经过期,改名,以便再次请求时,可以返回老截图 [AUTO-TRANSLATED:94fac79b]
|
||||
// Screenshot has expired, rename it so that it can be returned when requested again
|
||||
rename(path.data(), new_snap.data());
|
||||
have_old_snap = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//截图存在,且未过期,那么返回之
|
||||
// 截图存在,且未过期,那么返回之 [AUTO-TRANSLATED:6f53d3d1]
|
||||
// Screenshot exists and has not expired, so return it
|
||||
res_old_snap = true;
|
||||
responseSnap(path, allArgs.parser.getHeader(), invoker);
|
||||
//中断遍历
|
||||
// 中断遍历 [AUTO-TRANSLATED:7893aab3]
|
||||
// Interrupt traversal
|
||||
return false;
|
||||
});
|
||||
|
||||
if (res_old_snap) {
|
||||
//已经回复了旧的截图
|
||||
// 已经回复了旧的截图 [AUTO-TRANSLATED:9051a3e6]
|
||||
// Old screenshot has been replied
|
||||
return;
|
||||
}
|
||||
|
||||
//无截图或者截图已经过期
|
||||
// 无截图或者截图已经过期 [AUTO-TRANSLATED:89c46415]
|
||||
// No screenshot or screenshot has expired
|
||||
if (!have_old_snap) {
|
||||
//无过期截图,生成一个空文件,目的是顺便创建文件夹路径
|
||||
//同时防止在FFmpeg生成截图途中不停的尝试调用该api多次启动FFmpeg进程
|
||||
// 无过期截图,生成一个空文件,目的是顺便创建文件夹路径 [AUTO-TRANSLATED:bdbfdbcb]
|
||||
// No expired screenshot, generate an empty file, the purpose is to create the folder path by the way
|
||||
// 同时防止在FFmpeg生成截图途中不停的尝试调用该api多次启动FFmpeg进程 [AUTO-TRANSLATED:a04e1ee2]
|
||||
// At the same time, prevent the FFmpeg process from being started multiple times by continuously trying to call this API during the FFmpeg screenshot generation process
|
||||
auto file = File::create_file(new_snap, "wb");
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
//启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件
|
||||
// 启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件 [AUTO-TRANSLATED:7d589e3f]
|
||||
// Start the FFmpeg process, start taking screenshots, generate temporary files, replace them with formal files after successful screenshots
|
||||
auto new_snap_tmp = new_snap + ".tmp";
|
||||
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success, const string &err_msg) {
|
||||
if (!success) {
|
||||
//生成截图失败,可能残留空文件
|
||||
// 生成截图失败,可能残留空文件 [AUTO-TRANSLATED:c96a4468]
|
||||
// Screenshot generation failed, there may be residual empty files
|
||||
File::delete_file(new_snap_tmp);
|
||||
} else {
|
||||
//临时文件改成正式文件
|
||||
// 临时文件改成正式文件 [AUTO-TRANSLATED:eca24dfd]
|
||||
// Temporary file changed to formal file
|
||||
File::delete_file(new_snap);
|
||||
rename(new_snap_tmp.data(), new_snap.data());
|
||||
}
|
||||
@ -1889,7 +2027,8 @@ void installWebApi() {
|
||||
WebRtcPluginManager::Instance().negotiateSdp(session, type, *args, [invoker, offer, headerOut, location](const WebRtcInterface &exchanger) mutable {
|
||||
auto &handler = const_cast<WebRtcInterface &>(exchanger);
|
||||
try {
|
||||
// 设置返回类型
|
||||
// 设置返回类型 [AUTO-TRANSLATED:ffc2a31a]
|
||||
// Set return type
|
||||
headerOut["Content-Type"] = "application/sdp";
|
||||
headerOut["Location"] = location + "?id=" + exchanger.getIdentifier() + "&token=" + exchanger.deleteRandStr();
|
||||
invoker(201, headerOut, handler.getAnswerSdp(offer));
|
||||
@ -1938,17 +2077,22 @@ void installWebApi() {
|
||||
CHECK_ARGS("vhost", "app", "stream", "file_path");
|
||||
|
||||
ProtocolOption option;
|
||||
// mp4支持多track
|
||||
// mp4支持多track [AUTO-TRANSLATED:b9688762]
|
||||
// mp4 supports multiple tracks
|
||||
option.max_track = 16;
|
||||
// 默认解复用mp4不生成mp4
|
||||
// 默认解复用mp4不生成mp4 [AUTO-TRANSLATED:11f2dcee]
|
||||
// By default, demultiplexing mp4 does not generate mp4
|
||||
option.enable_mp4 = false;
|
||||
// 但是如果参数明确指定开启mp4, 那么也允许之
|
||||
// 但是如果参数明确指定开启mp4, 那么也允许之 [AUTO-TRANSLATED:b143a9e3]
|
||||
// But if the parameter explicitly specifies to enable mp4, then it is also allowed
|
||||
option.load(allArgs);
|
||||
// 强制无人观看时自动关闭
|
||||
// 强制无人观看时自动关闭 [AUTO-TRANSLATED:f7c85948]
|
||||
// Force automatic shutdown when no one is watching
|
||||
option.auto_close = true;
|
||||
auto tuple = MediaTuple{allArgs["vhost"], allArgs["app"], allArgs["stream"], ""};
|
||||
auto reader = std::make_shared<MP4Reader>(tuple, allArgs["file_path"], option);
|
||||
// sample_ms设置为0,从配置文件加载;file_repeat可以指定,如果配置文件也指定循环解复用,那么强制开启
|
||||
// sample_ms设置为0,从配置文件加载;file_repeat可以指定,如果配置文件也指定循环解复用,那么强制开启 [AUTO-TRANSLATED:23e826b4]
|
||||
// sample_ms is set to 0, loaded from the configuration file; file_repeat can be specified, if the configuration file also specifies loop demultiplexing, then force it to be enabled
|
||||
reader->startReadMP4(0, true, allArgs["file_repeat"]);
|
||||
});
|
||||
#endif
|
||||
@ -1983,7 +2127,8 @@ void installWebApi() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过on_http_access完成文件下载鉴权,请务必确认访问鉴权url参数以及访问文件路径是否合法
|
||||
// 通过on_http_access完成文件下载鉴权,请务必确认访问鉴权url参数以及访问文件路径是否合法 [AUTO-TRANSLATED:73507988]
|
||||
// File download authentication is completed through on_http_access. Please make sure that the access authentication URL parameters and the access file path are legal
|
||||
HttpSession::HttpAccessPathInvoker file_invoker = [allArgs, invoker](const string &err_msg, const string &cookie_path_in, int life_second) mutable {
|
||||
if (!err_msg.empty()) {
|
||||
invoker(401, StrCaseMap{}, err_msg);
|
||||
@ -1999,7 +2144,8 @@ void installWebApi() {
|
||||
|
||||
bool flag = NOTICE_EMIT(BroadcastHttpAccessArgs, Broadcast::kBroadcastHttpAccess, allArgs.parser, file_path, false, file_invoker, sender);
|
||||
if (!flag) {
|
||||
// 文件下载鉴权事件无人监听,不允许下载
|
||||
// 文件下载鉴权事件无人监听,不允许下载 [AUTO-TRANSLATED:5e02f0ce]
|
||||
// No one is listening to the file download authentication event, download is not allowed
|
||||
invoker(401, StrCaseMap {}, "None http access event listener");
|
||||
}
|
||||
});
|
||||
|
@ -19,16 +19,19 @@
|
||||
#include "Http/HttpSession.h"
|
||||
#include "Common/MultiMediaSourceMuxer.h"
|
||||
|
||||
//配置文件路径
|
||||
// 配置文件路径 [AUTO-TRANSLATED:8a373c2f]
|
||||
// Configuration file path
|
||||
extern std::string g_ini_file;
|
||||
|
||||
namespace mediakit {
|
||||
////////////RTSP服务器配置///////////
|
||||
// //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981]
|
||||
// //////////RTSP server configuration///////////
|
||||
namespace Rtsp {
|
||||
extern const std::string kPort;
|
||||
} //namespace Rtsp
|
||||
|
||||
////////////RTMP服务器配置///////////
|
||||
// //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f]
|
||||
// //////////RTMP server configuration///////////
|
||||
namespace Rtmp {
|
||||
extern const std::string kPort;
|
||||
} //namespace RTMP
|
||||
@ -153,19 +156,25 @@ using ArgsString = HttpAllArgs<std::string>;
|
||||
#define API_ARGS_STRING_ASYNC API_ARGS_STRING, const mediakit::HttpSession::HttpResponseInvoker &invoker
|
||||
#define API_ARGS_VALUE sender, headerOut, allArgs, val
|
||||
|
||||
//注册http请求参数是map<string, variant, StrCaseCompare>类型的http api
|
||||
// 注册http请求参数是map<string, variant, StrCaseCompare>类型的http api [AUTO-TRANSLATED:8a273897]
|
||||
// Register http request parameters as map<string, variant, StrCaseCompare> type http api
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_MAP)> &func);
|
||||
//注册http请求参数是map<string, variant, StrCaseCompare>类型,但是可以异步回复的的http api
|
||||
// 注册http请求参数是map<string, variant, StrCaseCompare>类型,但是可以异步回复的的http api [AUTO-TRANSLATED:9da5d5f5]
|
||||
// Register http request parameters as map<string, variant, StrCaseCompare> type, but can be replied asynchronously http api
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_MAP_ASYNC)> &func);
|
||||
|
||||
//注册http请求参数是Json::Value类型的http api(可以支持多级嵌套的json参数对象)
|
||||
// 注册http请求参数是Json::Value类型的http api(可以支持多级嵌套的json参数对象) [AUTO-TRANSLATED:c4794456]
|
||||
// Register http request parameters as Json::Value type http api (can support multi-level nested json parameter objects)
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_JSON)> &func);
|
||||
//注册http请求参数是Json::Value类型,但是可以异步回复的的http api
|
||||
// 注册http请求参数是Json::Value类型,但是可以异步回复的的http api [AUTO-TRANSLATED:742e57fd]
|
||||
// Register http request parameters as Json::Value type, but can be replied asynchronously http api
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_JSON_ASYNC)> &func);
|
||||
|
||||
//注册http请求参数是http原始请求信息的http api
|
||||
// 注册http请求参数是http原始请求信息的http api [AUTO-TRANSLATED:72d3fe93]
|
||||
// Register http request parameters as http original request information http api
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_STRING)> &func);
|
||||
//注册http请求参数是http原始请求信息的异步回复的http api
|
||||
// 注册http请求参数是http原始请求信息的异步回复的http api [AUTO-TRANSLATED:49feefa8]
|
||||
// Register http request parameters as http original request information asynchronous reply http api
|
||||
void api_regist(const std::string &api_path, const std::function<void(API_ARGS_STRING_ASYNC)> &func);
|
||||
|
||||
template<typename Args, typename First>
|
||||
@ -178,14 +187,17 @@ bool checkArgs(Args &args, const First &first, const KeyTypes &...keys) {
|
||||
return checkArgs(args, first) && checkArgs(args, keys...);
|
||||
}
|
||||
|
||||
//检查http url中或body中或http header参数是否为空的宏
|
||||
// 检查http url中或body中或http header参数是否为空的宏 [AUTO-TRANSLATED:9de001a4]
|
||||
// Check whether the http url, body or http header parameters are empty
|
||||
#define CHECK_ARGS(...) \
|
||||
if(!checkArgs(allArgs,##__VA_ARGS__)){ \
|
||||
throw InvalidArgsException("Required parameter missed: " #__VA_ARGS__); \
|
||||
}
|
||||
|
||||
// 检查http参数中是否附带secret密钥的宏,127.0.0.1的ip不检查密钥
|
||||
// 同时检测是否在ip白名单内
|
||||
// 检查http参数中是否附带secret密钥的宏,127.0.0.1的ip不检查密钥 [AUTO-TRANSLATED:7546956c]
|
||||
// Check whether the http parameters contain the secret key, the ip of 127.0.0.1 does not check the key
|
||||
// 同时检测是否在ip白名单内 [AUTO-TRANSLATED:d12f963d]
|
||||
// Check whether it is in the ip whitelist at the same time
|
||||
#define CHECK_SECRET() \
|
||||
do { \
|
||||
auto ip = sender.get_peer_ip(); \
|
||||
|
@ -56,7 +56,8 @@ const string kRetryDelay = HOOK_FIELD "retry_delay";
|
||||
static onceToken token([]() {
|
||||
mINI::Instance()[kEnable] = false;
|
||||
mINI::Instance()[kTimeoutSec] = 10;
|
||||
// 默认hook地址设置为空,采用默认行为(例如不鉴权)
|
||||
// 默认hook地址设置为空,采用默认行为(例如不鉴权) [AUTO-TRANSLATED:0e38bc3c]
|
||||
// Default hook address is set to empty, using default behavior (e.g. no authentication)
|
||||
mINI::Instance()[kOnPublish] = "";
|
||||
mINI::Instance()[kOnPlay] = "";
|
||||
mINI::Instance()[kOnFlowReport] = "";
|
||||
@ -134,7 +135,8 @@ static void parse_http_response(const SockException &ex, const Parser &res, cons
|
||||
fun(result, "", should_retry);
|
||||
} catch (std::exception &ex) {
|
||||
auto errStr = StrPrinter << "[do hook invoker failed]:" << ex.what() << endl;
|
||||
// 如果还是抛异常,那么再上抛异常
|
||||
// 如果还是抛异常,那么再上抛异常 [AUTO-TRANSLATED:cc66ff58]
|
||||
// If an exception is still thrown, then re-throw the exception
|
||||
fun(Json::nullValue, errStr, should_retry);
|
||||
}
|
||||
}
|
||||
@ -190,7 +192,8 @@ void do_http_hook(const string &url, const ArgsType &body, const function<void(c
|
||||
onceToken token(nullptr, [&]() mutable { requester.reset(); });
|
||||
parse_http_response(ex, res, [&](const Value &obj, const string &err, bool should_retry) {
|
||||
if (!err.empty()) {
|
||||
// hook失败
|
||||
// hook失败 [AUTO-TRANSLATED:68231f46]
|
||||
// Hook failed
|
||||
WarnL << "hook " << url << " " << ticker.elapsedTime() << "ms,failed" << err << ":" << bodyStr;
|
||||
|
||||
if (retry-- > 0 && should_retry) {
|
||||
@ -198,12 +201,14 @@ void do_http_hook(const string &url, const ArgsType &body, const function<void(c
|
||||
do_http_hook(url, body, func, retry);
|
||||
return 0;
|
||||
});
|
||||
// 重试不需要触发回调
|
||||
// 重试不需要触发回调 [AUTO-TRANSLATED:41917311]
|
||||
// Retry does not need to trigger callback
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (ticker.elapsedTime() > 500) {
|
||||
// hook成功,但是hook响应超过500ms,打印警告日志
|
||||
// hook成功,但是hook响应超过500ms,打印警告日志 [AUTO-TRANSLATED:e03557aa]
|
||||
// Hook succeeded, but hook response exceeded 500ms, print warning log
|
||||
DebugL << "hook " << url << " " << ticker.elapsedTime() << "ms,success:" << bodyStr;
|
||||
}
|
||||
|
||||
@ -240,7 +245,8 @@ static void reportServerStarted() {
|
||||
for (auto &pr : mINI::Instance()) {
|
||||
body[pr.first] = (string &)pr.second;
|
||||
}
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_server_started, body, nullptr);
|
||||
}
|
||||
|
||||
@ -252,11 +258,13 @@ static void reportServerExited() {
|
||||
}
|
||||
|
||||
const ArgsType body;
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_server_exited, body, nullptr);
|
||||
}
|
||||
|
||||
// 服务器定时保活定时器
|
||||
// 服务器定时保活定时器 [AUTO-TRANSLATED:2bb39e50]
|
||||
// Server keep-alive timer
|
||||
static Timer::Ptr g_keepalive_timer;
|
||||
static void reportServerKeepalive() {
|
||||
GET_CONFIG(bool, hook_enable, Hook::kEnable);
|
||||
@ -270,7 +278,8 @@ static void reportServerKeepalive() {
|
||||
getStatisticJson([](const Value &data) mutable {
|
||||
ArgsType body;
|
||||
body["data"] = data;
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_server_keepalive, body, nullptr);
|
||||
});
|
||||
return true;
|
||||
@ -285,7 +294,8 @@ static string getPullUrl(const string &origin_fmt, const MediaInfo &info) {
|
||||
WarnL << "get origin url failed, origin_fmt:" << origin_fmt;
|
||||
return "";
|
||||
}
|
||||
// 告知源站这是来自边沿站的拉流请求,如果未找到流请立即返回拉流失败
|
||||
// 告知源站这是来自边沿站的拉流请求,如果未找到流请立即返回拉流失败 [AUTO-TRANSLATED:adf0d210]
|
||||
// Inform the origin station that this is a pull stream request from the edge station, if the stream is not found, please return the pull stream failure immediately
|
||||
return string(url) + '?' + kEdgeServerParam + '&' + VHOST_KEY + '=' + info.vhost + '&' + info.params;
|
||||
}
|
||||
|
||||
@ -305,9 +315,11 @@ static void pullStreamFromOrigin(const vector<string> &urls, size_t index, size_
|
||||
if (!ex) {
|
||||
return;
|
||||
}
|
||||
// 拉流失败
|
||||
// 拉流失败 [AUTO-TRANSLATED:6d52eb25]
|
||||
// Pull stream failed
|
||||
if (++failed_cnt == urls.size()) {
|
||||
// 已经重试所有源站了
|
||||
// 已经重试所有源站了 [AUTO-TRANSLATED:b3b384a8]
|
||||
// All origin stations have been retried
|
||||
WarnL << "pull stream from origin final failed: " << url;
|
||||
closePlayer();
|
||||
return;
|
||||
@ -342,20 +354,24 @@ void installWebHook() {
|
||||
invoker("", ProtocolOption());
|
||||
return;
|
||||
}
|
||||
// 异步执行该hook api,防止阻塞NoticeCenter
|
||||
// 异步执行该hook api,防止阻塞NoticeCenter [AUTO-TRANSLATED:783f64c1]
|
||||
// Asynchronously execute this hook api to prevent blocking NoticeCenter
|
||||
auto body = make_json(args);
|
||||
body["ip"] = sender.get_peer_ip();
|
||||
body["port"] = sender.get_peer_port();
|
||||
body["id"] = sender.getIdentifier();
|
||||
body["originType"] = (int)type;
|
||||
body["originTypeStr"] = getOriginTypeString(type);
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_publish, body, [invoker](const Value &obj, const string &err) mutable {
|
||||
if (err.empty()) {
|
||||
// 推流鉴权成功
|
||||
// 推流鉴权成功 [AUTO-TRANSLATED:e4285dab]
|
||||
// Push stream authentication succeeded
|
||||
invoker(err, ProtocolOption(jsonToMini(obj)));
|
||||
} else {
|
||||
// 推流鉴权失败
|
||||
// 推流鉴权失败 [AUTO-TRANSLATED:780430e0]
|
||||
// Push stream authentication failed
|
||||
invoker(err, ProtocolOption());
|
||||
}
|
||||
});
|
||||
@ -371,7 +387,8 @@ void installWebHook() {
|
||||
body["ip"] = sender.get_peer_ip();
|
||||
body["port"] = sender.get_peer_port();
|
||||
body["id"] = sender.getIdentifier();
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_play, body, [invoker](const Value &obj, const string &err) { invoker(err); });
|
||||
});
|
||||
|
||||
@ -387,17 +404,20 @@ void installWebHook() {
|
||||
body["ip"] = sender.get_peer_ip();
|
||||
body["port"] = sender.get_peer_port();
|
||||
body["id"] = sender.getIdentifier();
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_flowreport, body, nullptr);
|
||||
});
|
||||
|
||||
static const string unAuthedRealm = "unAuthedRealm";
|
||||
|
||||
// 监听kBroadcastOnGetRtspRealm事件决定rtsp链接是否需要鉴权(传统的rtsp鉴权方案)才能访问
|
||||
// 监听kBroadcastOnGetRtspRealm事件决定rtsp链接是否需要鉴权(传统的rtsp鉴权方案)才能访问 [AUTO-TRANSLATED:00dc9fa3]
|
||||
// Listen to the kBroadcastOnGetRtspRealm event to determine whether the rtsp link needs authentication (traditional rtsp authentication scheme) to access
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastOnGetRtspRealm, [](BroadcastOnGetRtspRealmArgs) {
|
||||
GET_CONFIG(string, hook_rtsp_realm, Hook::kOnRtspRealm);
|
||||
if (!hook_enable || hook_rtsp_realm.empty()) {
|
||||
// 无需认证
|
||||
// 无需认证 [AUTO-TRANSLATED:77728e07]
|
||||
// No authentication required
|
||||
invoker("");
|
||||
return;
|
||||
}
|
||||
@ -405,10 +425,12 @@ void installWebHook() {
|
||||
body["ip"] = sender.get_peer_ip();
|
||||
body["port"] = sender.get_peer_port();
|
||||
body["id"] = sender.getIdentifier();
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_rtsp_realm, body, [invoker](const Value &obj, const string &err) {
|
||||
if (!err.empty()) {
|
||||
// 如果接口访问失败,那么该rtsp流认证失败
|
||||
// 如果接口访问失败,那么该rtsp流认证失败 [AUTO-TRANSLATED:81b19b72]
|
||||
// If the interface access fails, then the rtsp stream authentication fails
|
||||
invoker(unAuthedRealm);
|
||||
return;
|
||||
}
|
||||
@ -416,11 +438,13 @@ void installWebHook() {
|
||||
});
|
||||
});
|
||||
|
||||
// 监听kBroadcastOnRtspAuth事件返回正确的rtsp鉴权用户密码
|
||||
// 监听kBroadcastOnRtspAuth事件返回正确的rtsp鉴权用户密码 [AUTO-TRANSLATED:bcf1754e]
|
||||
// Listen to the kBroadcastOnRtspAuth event to return the correct rtsp authentication username and password
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastOnRtspAuth, [](BroadcastOnRtspAuthArgs) {
|
||||
GET_CONFIG(string, hook_rtsp_auth, Hook::kOnRtspAuth);
|
||||
if (unAuthedRealm == realm || !hook_enable || hook_rtsp_auth.empty()) {
|
||||
// 认证失败
|
||||
// 认证失败 [AUTO-TRANSLATED:70cf56ff]
|
||||
// Authentication failed
|
||||
invoker(false, makeRandStr(12));
|
||||
return;
|
||||
}
|
||||
@ -431,10 +455,12 @@ void installWebHook() {
|
||||
body["user_name"] = user_name;
|
||||
body["must_no_encrypt"] = must_no_encrypt;
|
||||
body["realm"] = realm;
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_rtsp_auth, body, [invoker](const Value &obj, const string &err) {
|
||||
if (!err.empty()) {
|
||||
// 认证失败
|
||||
// 认证失败 [AUTO-TRANSLATED:70cf56ff]
|
||||
// Authentication failed
|
||||
invoker(false, makeRandStr(12));
|
||||
return;
|
||||
}
|
||||
@ -442,7 +468,8 @@ void installWebHook() {
|
||||
});
|
||||
});
|
||||
|
||||
// 监听rtsp、rtmp源注册或注销事件
|
||||
// 监听rtsp、rtmp源注册或注销事件 [AUTO-TRANSLATED:6396afa8]
|
||||
// Listen to rtsp, rtmp source registration or deregistration events
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastMediaChanged, [](BroadcastMediaChangedArgs) {
|
||||
GET_CONFIG(string, hook_stream_changed, Hook::kOnStreamChanged);
|
||||
if (!hook_enable || hook_stream_changed.empty()) {
|
||||
@ -460,7 +487,8 @@ void installWebHook() {
|
||||
return ret;
|
||||
});
|
||||
if (!stream_changed_set.empty() && stream_changed_set.find(sender.getSchema()) == stream_changed_set.end()) {
|
||||
// 该协议注册注销事件被忽略
|
||||
// 该协议注册注销事件被忽略 [AUTO-TRANSLATED:87299c9d]
|
||||
// This protocol registration deregistration event is ignored
|
||||
return;
|
||||
}
|
||||
|
||||
@ -473,7 +501,8 @@ void installWebHook() {
|
||||
dumpMediaTuple(sender.getMediaTuple(), body);
|
||||
body["regist"] = bRegist;
|
||||
}
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_stream_changed, body, nullptr);
|
||||
});
|
||||
|
||||
@ -488,10 +517,12 @@ void installWebHook() {
|
||||
return ret;
|
||||
});
|
||||
|
||||
// 监听播放失败(未找到特定的流)事件
|
||||
// 监听播放失败(未找到特定的流)事件 [AUTO-TRANSLATED:ca8cc9ba]
|
||||
// Listen to playback failure (specific stream not found) event
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastNotFoundStream, [](BroadcastNotFoundStreamArgs) {
|
||||
if (!origin_urls.empty()) {
|
||||
// 设置了源站,那么尝试溯源
|
||||
// 设置了源站,那么尝试溯源 [AUTO-TRANSLATED:541a4ced]
|
||||
// If the source station is set, then try to trace the source
|
||||
static atomic<uint8_t> s_index { 0 };
|
||||
pullStreamFromOrigin(origin_urls, s_index.load(), 0, args, closePlayer);
|
||||
++s_index;
|
||||
@ -499,7 +530,8 @@ void installWebHook() {
|
||||
}
|
||||
|
||||
if (start_with(args.params, kEdgeServerParam)) {
|
||||
// 源站收到来自边沿站的溯源请求,流不存在时立即返回拉流失败
|
||||
// 源站收到来自边沿站的溯源请求,流不存在时立即返回拉流失败 [AUTO-TRANSLATED:5bd04a34]
|
||||
// The source station receives a trace request from the edge station, and immediately returns a pull stream failure if the stream does not exist
|
||||
closePlayer();
|
||||
return;
|
||||
}
|
||||
@ -513,7 +545,8 @@ void installWebHook() {
|
||||
body["port"] = sender.get_peer_port();
|
||||
body["id"] = sender.getIdentifier();
|
||||
|
||||
// Hook回复立即关闭流
|
||||
// Hook回复立即关闭流 [AUTO-TRANSLATED:2dcf7bd6]
|
||||
// Hook reply immediately closes the stream
|
||||
auto res_cb = [closePlayer](const Value &res, const string &err) {
|
||||
bool flag = res["close"].asBool();
|
||||
if (flag) {
|
||||
@ -521,7 +554,8 @@ void installWebHook() {
|
||||
}
|
||||
};
|
||||
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_stream_not_found, body, res_cb);
|
||||
});
|
||||
|
||||
@ -539,13 +573,15 @@ void installWebHook() {
|
||||
};
|
||||
|
||||
#ifdef ENABLE_MP4
|
||||
// 录制mp4文件成功后广播
|
||||
// 录制mp4文件成功后广播 [AUTO-TRANSLATED:479ec954]
|
||||
// Broadcast after recording the mp4 file successfully
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastRecordMP4, [](BroadcastRecordMP4Args) {
|
||||
GET_CONFIG(string, hook_record_mp4, Hook::kOnRecordMp4);
|
||||
if (!hook_enable || hook_record_mp4.empty()) {
|
||||
return;
|
||||
}
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_record_mp4, getRecordInfo(info), nullptr);
|
||||
});
|
||||
#endif // ENABLE_MP4
|
||||
@ -555,7 +591,8 @@ void installWebHook() {
|
||||
if (!hook_enable || hook_record_ts.empty()) {
|
||||
return;
|
||||
}
|
||||
// 执行 hook
|
||||
// 执行 hook [AUTO-TRANSLATED:d9d66f75]
|
||||
// Execute hook
|
||||
do_http_hook(hook_record_ts, getRecordInfo(info), nullptr);
|
||||
});
|
||||
|
||||
@ -572,13 +609,15 @@ void installWebHook() {
|
||||
body["user_name"] = user_name;
|
||||
body["passwd"] = passwd;
|
||||
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_shell_login, body, [invoker](const Value &, const string &err) { invoker(err); });
|
||||
});
|
||||
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastStreamNoneReader, [](BroadcastStreamNoneReaderArgs) {
|
||||
if (!origin_urls.empty() && sender.getOriginType() == MediaOriginType::pull) {
|
||||
// 边沿站无人观看时如果是拉流的则立即停止溯源
|
||||
// 边沿站无人观看时如果是拉流的则立即停止溯源 [AUTO-TRANSLATED:a1429c77]
|
||||
// If no one is watching at the edge station, stop tracing immediately if it is pulling
|
||||
sender.close(false);
|
||||
WarnL << "无人观看主动关闭流:" << sender.getOriginUrl();
|
||||
return;
|
||||
@ -592,7 +631,8 @@ void installWebHook() {
|
||||
body["schema"] = sender.getSchema();
|
||||
dumpMediaTuple(sender.getMediaTuple(), body);
|
||||
weak_ptr<MediaSource> weakSrc = sender.shared_from_this();
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_stream_none_reader, body, [weakSrc](const Value &obj, const string &err) {
|
||||
bool flag = obj["close"].asBool();
|
||||
auto strongSrc = weakSrc.lock();
|
||||
@ -618,7 +658,8 @@ void installWebHook() {
|
||||
body["originUrl"] = sender.getOriginUrl(MediaSource::NullMediaSource());
|
||||
body["msg"] = ex.what();
|
||||
body["err"] = ex.getErrCode();
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_send_rtp_stopped, body, nullptr);
|
||||
});
|
||||
|
||||
@ -629,19 +670,36 @@ void installWebHook() {
|
||||
* 3、cookie标记是否有权限访问文件,如果有权限,直接返回文件
|
||||
* 4、cookie中记录的url参数是否跟本次url参数一致,如果一致直接返回客户端错误码
|
||||
* 5、触发kBroadcastHttpAccess事件
|
||||
* kBroadcastHttpAccess event trigger mechanism
|
||||
* 1. Find the cookie according to the http request header, and find it to enter step 3
|
||||
* 2. Find the cookie according to the http url parameter, if the cookie is still not found, enter step 5
|
||||
* 3. The cookie marks whether it has permission to access the file, if it has permission, return the file directly
|
||||
* 4. Whether the url parameter recorded in the cookie is consistent with the current url parameter, if it is consistent, return the client error code directly
|
||||
* 5. Trigger the kBroadcastHttpAccess event
|
||||
|
||||
* [AUTO-TRANSLATED:ecd819e5]
|
||||
*/
|
||||
// 开发者应该通过该事件判定http客户端是否有权限访问http服务器上的特定文件
|
||||
// ZLMediaKit会记录本次鉴权的结果至cookie
|
||||
// 如果鉴权成功,在cookie有效期内,那么下次客户端再访问授权目录时,ZLMediaKit会直接返回文件
|
||||
// 如果鉴权失败,在cookie有效期内,如果http url参数不变(否则会立即再次触发鉴权事件),ZLMediaKit会直接返回错误码
|
||||
// 如果用户客户端不支持cookie,那么ZLMediaKit会根据url参数查找cookie并追踪用户,
|
||||
// 如果没有url参数,客户端又不支持cookie,那么会根据ip和端口追踪用户
|
||||
// 追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能
|
||||
// 开发者应该通过该事件判定http客户端是否有权限访问http服务器上的特定文件 [AUTO-TRANSLATED:938b8bc5]
|
||||
// Developers should use this event to determine whether the http client has permission to access specific files on the http server
|
||||
// ZLMediaKit会记录本次鉴权的结果至cookie [AUTO-TRANSLATED:b051ea2e]
|
||||
// ZLMediaKit will record the result of this authentication to the cookie
|
||||
// 如果鉴权成功,在cookie有效期内,那么下次客户端再访问授权目录时,ZLMediaKit会直接返回文件 [AUTO-TRANSLATED:be12a468]
|
||||
// If the authentication is successful, within the validity period of the cookie, the next time the client accesses the authorized directory, ZLMediaKit will return the file directly
|
||||
// 如果鉴权失败,在cookie有效期内,如果http url参数不变(否则会立即再次触发鉴权事件),ZLMediaKit会直接返回错误码 [AUTO-TRANSLATED:6396137d]
|
||||
// If the authentication fails, within the validity period of the cookie, if the http url parameter remains unchanged (otherwise the authentication event will be triggered immediately), ZLMediaKit will return the error code directly
|
||||
// 如果用户客户端不支持cookie,那么ZLMediaKit会根据url参数查找cookie并追踪用户, [AUTO-TRANSLATED:6fd2e366]
|
||||
// If the user client does not support cookies, then ZLMediaKit will find the cookie according to the url parameter and track the user,
|
||||
// 如果没有url参数,客户端又不支持cookie,那么会根据ip和端口追踪用户 [AUTO-TRANSLATED:85a780ea]
|
||||
// If there is no url parameter and the client does not support cookies, then the user will be tracked according to the ip and port
|
||||
// 追踪用户的目的是为了缓存上次鉴权结果,减少鉴权次数,提高性能 [AUTO-TRANSLATED:22827145]
|
||||
// The purpose of tracking users is to cache the last authentication result, reduce the number of authentication times, and improve performance
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastHttpAccess, [](BroadcastHttpAccessArgs) {
|
||||
GET_CONFIG(string, hook_http_access, Hook::kOnHttpAccess);
|
||||
if (!hook_enable || hook_http_access.empty()) {
|
||||
// 未开启http文件访问鉴权,那么允许访问,但是每次访问都要鉴权;
|
||||
// 因为后续随时都可能开启鉴权(重载配置文件后可能重新开启鉴权)
|
||||
// 未开启http文件访问鉴权,那么允许访问,但是每次访问都要鉴权; [AUTO-TRANSLATED:deb3a0ae]
|
||||
// If http file access authentication is not enabled, then access is allowed, but authentication is required for each access;
|
||||
// 因为后续随时都可能开启鉴权(重载配置文件后可能重新开启鉴权) [AUTO-TRANSLATED:a090bf06]
|
||||
// Because authentication may be enabled at any time in the future (authentication may be re-enabled after reloading the configuration file)
|
||||
if (!HttpFileManager::isIPAllowed(sender.get_peer_ip())) {
|
||||
invoker("Your ip is not allowed to access the service.", "", 0);
|
||||
} else {
|
||||
@ -660,16 +718,21 @@ void installWebHook() {
|
||||
for (auto &pr : parser.getHeader()) {
|
||||
body[string("header.") + pr.first] = pr.second;
|
||||
}
|
||||
// 执行hook
|
||||
// 执行hook [AUTO-TRANSLATED:1df68201]
|
||||
// Execute hook
|
||||
do_http_hook(hook_http_access, body, [invoker](const Value &obj, const string &err) {
|
||||
if (!err.empty()) {
|
||||
// 如果接口访问失败,那么仅限本次没有访问http服务器的权限
|
||||
// 如果接口访问失败,那么仅限本次没有访问http服务器的权限 [AUTO-TRANSLATED:f8afd1fd]
|
||||
// If the interface access fails, then only this time does not have permission to access the http server
|
||||
invoker(err, "", 0);
|
||||
return;
|
||||
}
|
||||
// err参数代表不能访问的原因,空则代表可以访问
|
||||
// path参数是该客户端能访问或被禁止的顶端目录,如果path为空字符串,则表述为当前目录
|
||||
// second参数规定该cookie超时时间,如果second为0,本次鉴权结果不缓存
|
||||
// err参数代表不能访问的原因,空则代表可以访问 [AUTO-TRANSLATED:87dd19b9]
|
||||
// The err parameter represents the reason why it cannot be accessed, empty means it can be accessed
|
||||
// path参数是该客户端能访问或被禁止的顶端目录,如果path为空字符串,则表述为当前目录 [AUTO-TRANSLATED:b883a448]
|
||||
// The path parameter is the top directory that this client can access or is prohibited, if path is an empty string, it means the current directory
|
||||
// second参数规定该cookie超时时间,如果second为0,本次鉴权结果不缓存 [AUTO-TRANSLATED:1a0b9eb1]
|
||||
// The second parameter specifies the timeout time of this cookie, if second is 0, the result of this authentication will not be cached
|
||||
invoker(obj["err"].asString(), obj["path"].asString(), obj["second"].asInt());
|
||||
});
|
||||
});
|
||||
@ -691,10 +754,12 @@ void installWebHook() {
|
||||
do_http_hook(rtp_server_timeout, body);
|
||||
});
|
||||
|
||||
// 汇报服务器重新启动
|
||||
// 汇报服务器重新启动 [AUTO-TRANSLATED:bd7d83df]
|
||||
// Report server restart
|
||||
reportServerStarted();
|
||||
|
||||
// 定时上报保活
|
||||
// 定时上报保活 [AUTO-TRANSLATED:bd2364a0]
|
||||
// Report keep-alive regularly
|
||||
reportServerKeepalive();
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
#include <functional>
|
||||
#include "json/json.h"
|
||||
|
||||
//支持json或urlencoded方式传输参数
|
||||
// 支持json或urlencoded方式传输参数 [AUTO-TRANSLATED:0e14d484]
|
||||
// // Support json or urlencoded way to transmit parameters
|
||||
#define JSON_ARGS
|
||||
|
||||
#ifdef JSON_ARGS
|
||||
@ -25,7 +26,8 @@ typedef mediakit::HttpArgs ArgsType;
|
||||
#endif
|
||||
|
||||
namespace Hook {
|
||||
//web hook回复最大超时时间
|
||||
// web hook回复最大超时时间 [AUTO-TRANSLATED:9a059363]
|
||||
// Maximum timeout for web hook reply
|
||||
extern const std::string kTimeoutSec;
|
||||
}//namespace Hook
|
||||
|
||||
@ -37,6 +39,13 @@ void onProcessExited();
|
||||
* @param url 请求地址
|
||||
* @param body 请求body
|
||||
* @param func 回调
|
||||
* Trigger http hook request
|
||||
* @param url Request address
|
||||
* @param body Request body
|
||||
* @param func Callback
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8ffdd09b]
|
||||
*/
|
||||
void do_http_hook(const std::string &url, const ArgsType &body, const std::function<void(const Json::Value &, const std::string &)> &func = nullptr);
|
||||
#endif //ZLMEDIAKIT_WEBHOOK_H
|
||||
|
123
server/main.cpp
123
server/main.cpp
@ -50,7 +50,8 @@ using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
namespace mediakit {
|
||||
////////////HTTP配置///////////
|
||||
// //////////HTTP配置/////////// [AUTO-TRANSLATED:a281d694]
|
||||
// //////////HTTP configuration///////////
|
||||
namespace Http {
|
||||
#define HTTP_FIELD "http."
|
||||
const string kPort = HTTP_FIELD"port";
|
||||
@ -61,7 +62,8 @@ onceToken token1([](){
|
||||
},nullptr);
|
||||
}//namespace Http
|
||||
|
||||
////////////SHELL配置///////////
|
||||
// //////////SHELL配置/////////// [AUTO-TRANSLATED:f023ec45]
|
||||
// //////////SHELL configuration///////////
|
||||
namespace Shell {
|
||||
#define SHELL_FIELD "shell."
|
||||
const string kPort = SHELL_FIELD"port";
|
||||
@ -70,7 +72,8 @@ onceToken token1([](){
|
||||
},nullptr);
|
||||
} //namespace Shell
|
||||
|
||||
////////////RTSP服务器配置///////////
|
||||
// //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981]
|
||||
// //////////RTSP server configuration///////////
|
||||
namespace Rtsp {
|
||||
#define RTSP_FIELD "rtsp."
|
||||
const string kPort = RTSP_FIELD"port";
|
||||
@ -82,7 +85,8 @@ onceToken token1([](){
|
||||
|
||||
} //namespace Rtsp
|
||||
|
||||
////////////RTMP服务器配置///////////
|
||||
// //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f]
|
||||
// //////////RTMP server configuration///////////
|
||||
namespace Rtmp {
|
||||
#define RTMP_FIELD "rtmp."
|
||||
const string kPort = RTMP_FIELD"port";
|
||||
@ -93,7 +97,8 @@ onceToken token1([](){
|
||||
},nullptr);
|
||||
} //namespace RTMP
|
||||
|
||||
////////////Rtp代理相关配置///////////
|
||||
// //////////Rtp代理相关配置/////////// [AUTO-TRANSLATED:7b285587]
|
||||
// //////////Rtp proxy related configuration///////////
|
||||
namespace RtpProxy {
|
||||
#define RTP_PROXY_FIELD "rtp_proxy."
|
||||
const string kPort = RTP_PROXY_FIELD"port";
|
||||
@ -171,7 +176,8 @@ public:
|
||||
#if defined(ENABLE_VERSION)
|
||||
(*_parser) << Option('v', "version", Option::ArgNone, nullptr, false, "显示版本号",
|
||||
[](const std::shared_ptr<ostream> &stream, const string &arg) -> bool {
|
||||
//版本信息
|
||||
// 版本信息 [AUTO-TRANSLATED:d4cc59b2]
|
||||
// Version information
|
||||
*stream << "编译日期: " << BUILD_TIME << std::endl;
|
||||
*stream << "代码日期: " << COMMIT_TIME << std::endl;
|
||||
*stream << "当前git分支: " << BRANCH_NAME << std::endl;
|
||||
@ -205,7 +211,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//全局变量,在WebApi中用于保存配置文件用
|
||||
// 全局变量,在WebApi中用于保存配置文件用 [AUTO-TRANSLATED:6d5585ca]
|
||||
// Global variable, used in WebApi to save configuration files
|
||||
string g_ini_file;
|
||||
|
||||
int start_main(int argc,char *argv[]) {
|
||||
@ -228,11 +235,13 @@ int start_main(int argc,char *argv[]) {
|
||||
int threads = cmd_main["threads"];
|
||||
bool affinity = cmd_main["affinity"];
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", logLevel));
|
||||
#if !defined(ANDROID)
|
||||
auto fileChannel = std::make_shared<FileChannel>("FileChannel", cmd_main["log-dir"], logLevel);
|
||||
// 日志最多保存天数
|
||||
// 日志最多保存天数 [AUTO-TRANSLATED:9bfa8a9a]
|
||||
// Maximum number of days to save logs
|
||||
fileChannel->setMaxDay(cmd_main["max_day"]);
|
||||
fileChannel->setFileMaxCount(cmd_main["log-slice"]);
|
||||
fileChannel->setFileMaxSize(cmd_main["log-size"]);
|
||||
@ -243,24 +252,29 @@ int start_main(int argc,char *argv[]) {
|
||||
pid_t pid = getpid();
|
||||
bool kill_parent_if_failed = true;
|
||||
if (bDaemon) {
|
||||
//启动守护进程
|
||||
// 启动守护进程 [AUTO-TRANSLATED:33b2c5be]
|
||||
// Start daemon process
|
||||
System::startDaemon(kill_parent_if_failed);
|
||||
}
|
||||
//开启崩溃捕获等
|
||||
// 开启崩溃捕获等 [AUTO-TRANSLATED:9c7c759c]
|
||||
// Enable crash capture, etc.
|
||||
System::systemSetup();
|
||||
#endif//!defined(_WIN32)
|
||||
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:c93cc6f4]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
InfoL << kServerName;
|
||||
|
||||
//加载配置文件,如果配置文件不存在就创建一个
|
||||
// 加载配置文件,如果配置文件不存在就创建一个 [AUTO-TRANSLATED:761e7479]
|
||||
// Load configuration file, create one if it doesn't exist
|
||||
loadIniConfig(g_ini_file.data());
|
||||
|
||||
auto &secret = mINI::Instance()[API::kSecret];
|
||||
if (secret == "035c73f7-bb6b-4889-a715-d9eb2d1925cc" || secret.empty()) {
|
||||
// 使用默认secret被禁止启动
|
||||
// 使用默认secret被禁止启动 [AUTO-TRANSLATED:6295164b]
|
||||
// Starting with the default secret is prohibited
|
||||
secret = makeRandStr(32, true);
|
||||
mINI::Instance().dumpFile(g_ini_file);
|
||||
WarnL << "The " << API::kSecret << " is invalid, modified it to: " << secret
|
||||
@ -268,13 +282,16 @@ int start_main(int argc,char *argv[]) {
|
||||
}
|
||||
|
||||
if (!File::is_dir(ssl_file)) {
|
||||
// 不是文件夹,加载证书,证书包含公钥和私钥
|
||||
// 不是文件夹,加载证书,证书包含公钥和私钥 [AUTO-TRANSLATED:5d3a5e49]
|
||||
// Not a folder, load certificate, certificate contains public key and private key
|
||||
SSL_Initor::Instance().loadCertificate(ssl_file.data());
|
||||
} else {
|
||||
//加载文件夹下的所有证书
|
||||
// 加载文件夹下的所有证书 [AUTO-TRANSLATED:0e1f9b20]
|
||||
// Load all certificates under the folder
|
||||
File::scanDir(ssl_file,[](const string &path, bool isDir){
|
||||
if (!isDir) {
|
||||
// 最后的一个证书会当做默认证书(客户端ssl握手时未指定主机)
|
||||
// 最后的一个证书会当做默认证书(客户端ssl握手时未指定主机) [AUTO-TRANSLATED:b242685c]
|
||||
// The last certificate will be used as the default certificate (client ssl handshake does not specify the host)
|
||||
SSL_Initor::Instance().loadCertificate(path.data());
|
||||
}
|
||||
return true;
|
||||
@ -291,37 +308,46 @@ int start_main(int argc,char *argv[]) {
|
||||
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
|
||||
uint16_t rtpPort = mINI::Instance()[RtpProxy::kPort];
|
||||
|
||||
//设置poller线程数和cpu亲和性,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效
|
||||
//如果需要调用getSnap和addFFmpegSource接口,可以关闭cpu亲和性
|
||||
// 设置poller线程数和cpu亲和性,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效 [AUTO-TRANSLATED:7f03a1e5]
|
||||
// Set the number of poller threads and CPU affinity. This function must be called before using ZLToolKit network related objects to take effect.
|
||||
// 如果需要调用getSnap和addFFmpegSource接口,可以关闭cpu亲和性 [AUTO-TRANSLATED:7629f7bc]
|
||||
// If you need to call the getSnap and addFFmpegSource interfaces, you can turn off CPU affinity
|
||||
|
||||
EventPollerPool::setPoolSize(threads);
|
||||
WorkThreadPool::setPoolSize(threads);
|
||||
EventPollerPool::enableCpuAffinity(affinity);
|
||||
|
||||
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
||||
//测试方法:telnet 127.0.0.1 9000
|
||||
// 简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象 [AUTO-TRANSLATED:f9324c6e]
|
||||
// Simple telnet server, can be used for server debugging, but cannot use port 23, otherwise telnet will have inexplicable phenomena
|
||||
// 测试方法:telnet 127.0.0.1 9000 [AUTO-TRANSLATED:de0ac883]
|
||||
// Test method: telnet 127.0.0.1 9000
|
||||
auto shellSrv = std::make_shared<TcpServer>();
|
||||
|
||||
//rtsp[s]服务器, 可用于诸如亚马逊echo show这样的设备访问
|
||||
// rtsp[s]服务器, 可用于诸如亚马逊echo show这样的设备访问 [AUTO-TRANSLATED:f28e54f7]
|
||||
// rtsp[s] server, can be used for devices such as Amazon Echo Show to access
|
||||
auto rtspSrv = std::make_shared<TcpServer>();
|
||||
auto rtspSSLSrv = std::make_shared<TcpServer>();
|
||||
|
||||
//rtmp[s]服务器
|
||||
// rtmp[s]服务器 [AUTO-TRANSLATED:3ac98bf5]
|
||||
// rtmp[s] server
|
||||
auto rtmpSrv = std::make_shared<TcpServer>();
|
||||
auto rtmpsSrv = std::make_shared<TcpServer>();
|
||||
|
||||
//http[s]服务器
|
||||
// http[s]服务器 [AUTO-TRANSLATED:5bbc8735]
|
||||
// http[s] server
|
||||
auto httpSrv = std::make_shared<TcpServer>();
|
||||
auto httpsSrv = std::make_shared<TcpServer>();
|
||||
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
//GB28181 rtp推流端口,支持UDP/TCP
|
||||
// GB28181 rtp推流端口,支持UDP/TCP [AUTO-TRANSLATED:8a9b2872]
|
||||
// GB28181 rtp push stream port, supports UDP/TCP
|
||||
auto rtpServer = std::make_shared<RtpServer>();
|
||||
#endif//defined(ENABLE_RTPPROXY)
|
||||
|
||||
#if defined(ENABLE_WEBRTC)
|
||||
auto rtcSrv_tcp = std::make_shared<TcpServer>();
|
||||
//webrtc udp服务器
|
||||
// webrtc udp服务器 [AUTO-TRANSLATED:157a64e5]
|
||||
// webrtc udp server
|
||||
auto rtcSrv_udp = std::make_shared<UdpServer>();
|
||||
rtcSrv_udp->setOnCreateSocket([](const EventPoller::Ptr &poller, const Buffer::Ptr &buf, struct sockaddr *, int) {
|
||||
if (!buf) {
|
||||
@ -329,7 +355,8 @@ int start_main(int argc,char *argv[]) {
|
||||
}
|
||||
auto new_poller = WebRtcSession::queryPoller(buf);
|
||||
if (!new_poller) {
|
||||
//该数据对应的webrtc对象未找到,丢弃之
|
||||
// 该数据对应的webrtc对象未找到,丢弃之 [AUTO-TRANSLATED:d401f8cb]
|
||||
// The webrtc object corresponding to this data is not found, discard it
|
||||
return Socket::Ptr();
|
||||
}
|
||||
return Socket::createSocket(new_poller, false);
|
||||
@ -347,7 +374,8 @@ int start_main(int argc,char *argv[]) {
|
||||
}
|
||||
auto new_poller = SRT::SrtSession::queryPoller(buf);
|
||||
if (!new_poller) {
|
||||
//握手第一阶段
|
||||
// 握手第一阶段 [AUTO-TRANSLATED:6b3abcd4]
|
||||
// Handshake phase one
|
||||
return Socket::createSocket(poller, false);
|
||||
}
|
||||
return Socket::createSocket(new_poller, false);
|
||||
@ -362,31 +390,40 @@ int start_main(int argc,char *argv[]) {
|
||||
InfoL << "已启动http hook 接口";
|
||||
|
||||
try {
|
||||
//rtsp服务器,端口默认554
|
||||
// rtsp服务器,端口默认554 [AUTO-TRANSLATED:07937d81]
|
||||
// rtsp server, default port 554
|
||||
if (rtspPort) { rtspSrv->start<RtspSession>(rtspPort, listen_ip); }
|
||||
//rtsps服务器,端口默认322
|
||||
// rtsps服务器,端口默认322 [AUTO-TRANSLATED:e8a9fd71]
|
||||
// rtsps server, default port 322
|
||||
if (rtspsPort) { rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort, listen_ip); }
|
||||
|
||||
//rtmp服务器,端口默认1935
|
||||
// rtmp服务器,端口默认1935 [AUTO-TRANSLATED:58324c74]
|
||||
// rtmp server, default port 1935
|
||||
if (rtmpPort) { rtmpSrv->start<RtmpSession>(rtmpPort, listen_ip); }
|
||||
//rtmps服务器,端口默认19350
|
||||
// rtmps服务器,端口默认19350 [AUTO-TRANSLATED:c565ff4e]
|
||||
// rtmps server, default port 19350
|
||||
if (rtmpsPort) { rtmpsSrv->start<RtmpSessionWithSSL>(rtmpsPort, listen_ip); }
|
||||
|
||||
//http服务器,端口默认80
|
||||
// http服务器,端口默认80 [AUTO-TRANSLATED:8899e852]
|
||||
// http server, default port 80
|
||||
if (httpPort) { httpSrv->start<HttpSession>(httpPort, listen_ip); }
|
||||
//https服务器,端口默认443
|
||||
// https服务器,端口默认443 [AUTO-TRANSLATED:24999616]
|
||||
// https server, default port 443
|
||||
if (httpsPort) { httpsSrv->start<HttpsSession>(httpsPort, listen_ip); }
|
||||
|
||||
//telnet远程调试服务器
|
||||
// telnet远程调试服务器 [AUTO-TRANSLATED:577cb7cf]
|
||||
// telnet remote debug server
|
||||
if (shellPort) { shellSrv->start<ShellSession>(shellPort, listen_ip); }
|
||||
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
//创建rtp服务器
|
||||
// 创建rtp服务器 [AUTO-TRANSLATED:873f7f52]
|
||||
// create rtp server
|
||||
if (rtpPort) { rtpServer->start(rtpPort, listen_ip.c_str()); }
|
||||
#endif//defined(ENABLE_RTPPROXY)
|
||||
|
||||
#if defined(ENABLE_WEBRTC)
|
||||
//webrtc udp服务器
|
||||
// webrtc udp服务器 [AUTO-TRANSLATED:157a64e5]
|
||||
// webrtc udp server
|
||||
if (rtcPort) { rtcSrv_udp->start<WebRtcSession>(rtcPort, listen_ip);}
|
||||
|
||||
if (rtcTcpPort) { rtcSrv_tcp->start<WebRtcSession>(rtcTcpPort, listen_ip);}
|
||||
@ -394,7 +431,8 @@ int start_main(int argc,char *argv[]) {
|
||||
#endif//defined(ENABLE_WEBRTC)
|
||||
|
||||
#if defined(ENABLE_SRT)
|
||||
// srt udp服务器
|
||||
// srt udp服务器 [AUTO-TRANSLATED:06911727]
|
||||
// srt udp server
|
||||
if (srtPort) { srtSrv->start<SRT::SrtSession>(srtPort, listen_ip); }
|
||||
#endif//defined(ENABLE_SRT)
|
||||
|
||||
@ -403,14 +441,16 @@ int start_main(int argc,char *argv[]) {
|
||||
sleep(1);
|
||||
#if !defined(_WIN32)
|
||||
if (pid != getpid() && kill_parent_if_failed) {
|
||||
//杀掉守护进程
|
||||
// 杀掉守护进程 [AUTO-TRANSLATED:bee035e9]
|
||||
// kill the daemon process
|
||||
kill(pid, SIGINT);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// set exit signal handler
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) {
|
||||
InfoL << "SIGINT:exit";
|
||||
@ -433,7 +473,8 @@ int start_main(int argc,char *argv[]) {
|
||||
unInstallWebHook();
|
||||
onProcessExited();
|
||||
|
||||
//休眠1秒再退出,防止资源释放顺序错误
|
||||
// 休眠1秒再退出,防止资源释放顺序错误 [AUTO-TRANSLATED:1b11a74f]
|
||||
// sleep for 1 second before exiting, to prevent resource release order errors
|
||||
InfoL << "程序退出中,请等待...";
|
||||
sleep(1);
|
||||
InfoL << "程序退出完毕!";
|
||||
|
@ -19,7 +19,8 @@ namespace mediakit {
|
||||
H264Encoder::H264Encoder() {}
|
||||
|
||||
H264Encoder::~H264Encoder() {
|
||||
//* 清除图像区域
|
||||
// * 清除图像区域 [AUTO-TRANSLATED:6b316309]
|
||||
// * Clear image area
|
||||
if (_pPicIn) {
|
||||
delete _pPicIn;
|
||||
_pPicIn = nullptr;
|
||||
@ -29,7 +30,8 @@ H264Encoder::~H264Encoder() {
|
||||
_pPicOut = nullptr;
|
||||
}
|
||||
|
||||
//* 关闭编码器句柄
|
||||
// * 关闭编码器句柄 [AUTO-TRANSLATED:bf4a14e5]
|
||||
// * Close encoder handle
|
||||
if (_pX264Handle) {
|
||||
x264_encoder_close(_pX264Handle);
|
||||
_pX264Handle = nullptr;
|
||||
@ -206,6 +208,178 @@ Value的值就是fps。
|
||||
* i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones.
|
||||
* Not used when x264_encoder_reconfig is called directly.
|
||||
void (*param_free)( void* );
|
||||
/*typedef struct x264_param_t
|
||||
{
|
||||
CPU flag bit
|
||||
unsigned int cpu;
|
||||
int i_threads; Parallel encoding of multiple frames
|
||||
int b_deterministic; Whether to allow non-deterministic thread optimization
|
||||
int i_sync_lookahead; Thread pre-buffering
|
||||
|
||||
Video attributes
|
||||
int i_width; Width
|
||||
int i_height; Height
|
||||
int i_csp; CSP of the encoded bitstream, only supports i420, color space setting
|
||||
int i_level_idc; Setting of the level value
|
||||
int i_frame_total; Total number of encoded frames, default 0
|
||||
Vui parameter set video availability information video standardization options
|
||||
struct
|
||||
{
|
||||
they will be reduced to be 0 < x <= 65535 and prime
|
||||
int i_sar_height;
|
||||
int i_sar_width; Set aspect ratio
|
||||
|
||||
int i_overscan; 0=undef, 1=no overscan, 2=overscan Overscan lines, default "undef" (not set), options: show (watch) / crop (remove)
|
||||
|
||||
See the following value h264 appendix E
|
||||
Int i_vidformat; Video format, default "undef", component/pal/ntsc/secam/mac/undef
|
||||
int b_fullrange; Specify full range samples setting, default "off", options: off/on
|
||||
int i_colorprim; Original chroma format, default "undef", options: undef/bt709/bt470m/bt470bg, smpte170m/smpte240m/film
|
||||
int i_transfer; Conversion method, default "undef", options: undef/bt709/bt470m/bt470bg/linear,log100/log316/smpte170m/smpte240m
|
||||
int i_colmatrix; Chroma matrix setting, default "undef", undef/bt709/fcc/bt470bg, smpte170m/smpte240m/GBR/YCgCo
|
||||
int i_chroma_loc; both top & bottom chroma samples specified, range 0~5, default 0
|
||||
} vui;
|
||||
|
||||
int i_fps_num;
|
||||
int i_fps_den;
|
||||
These two parameters are determined by the fps frame rate, the assignment process is as follows:
|
||||
{ float fps;
|
||||
if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 )
|
||||
;
|
||||
else if( sscanf( value, "%f", &fps ) )
|
||||
{
|
||||
p->i_fps_num = (int)(fps * 1000 + .5);
|
||||
p->i_fps_den = 1000;
|
||||
}
|
||||
else
|
||||
b_error = 1;
|
||||
}
|
||||
The value of Value is fps.
|
||||
|
||||
Stream parameters
|
||||
int i_frame_reference; Maximum number of reference frames
|
||||
int i_keyint_max; Set IDR keyframe at this interval
|
||||
int i_keyint_min; Scene switching less than this value encodes as I, not IDR.
|
||||
int i_scenecut_threshold; How actively to insert additional I frames
|
||||
int i_bframe; Number of P frames between two related images
|
||||
int i_bframe_adaptive; Adaptive B frame determination
|
||||
int i_bframe_bias; Control the insertion of B frame determination, range -100~+100, the higher the easier it is to insert B frame, default 0
|
||||
int b_bframe_pyramid; Allow some B to be reference frames
|
||||
Parameters required for deblocking filter
|
||||
int b_deblocking_filter;
|
||||
int i_deblocking_filter_alphac0; [-6, 6] -6 light filter, 6 strong
|
||||
int i_deblocking_filter_beta; [-6, 6] idem
|
||||
Entropy coding
|
||||
int b_cabac;
|
||||
int i_cabac_init_idc;
|
||||
|
||||
int b_interlaced; Interlaced scanning
|
||||
Quantization
|
||||
int i_cqm_preset; Custom quantization matrix (CQM), initialize quantization mode to flat
|
||||
char *psz_cqm_file; JM format reads external quantization matrix file in JM format, automatically ignores other —cqm options
|
||||
uint8_t cqm_4iy[16]; used only if i_cqm_preset == X264_CQM_CUSTOM
|
||||
uint8_t cqm_4ic[16];
|
||||
uint8_t cqm_4py[16];
|
||||
uint8_t cqm_4pc[16];
|
||||
uint8_t cqm_8iy[64];
|
||||
uint8_t cqm_8py[64];
|
||||
|
||||
Log
|
||||
void (*pf_log)( void *, int i_level, const char *psz, va_list );
|
||||
void *p_log_private;
|
||||
int i_log_level;
|
||||
int b_visualize;
|
||||
char *psz_dump_yuv; Name of the reconstructed frame
|
||||
|
||||
Encoding analysis parameters
|
||||
struct
|
||||
{
|
||||
unsigned int intra; Inter-frame partition
|
||||
unsigned int inter; Intra-frame partition
|
||||
|
||||
int b_transform_8x8; Inter-frame partition
|
||||
int b_weighted_bipred; Implicit weighting for b frames
|
||||
int i_direct_mv_pred; Time-space motion prediction
|
||||
int i_chroma_qp_offset; Chroma quantization step offset
|
||||
|
||||
int i_me_method; Motion estimation algorithm (X264_ME_*)
|
||||
int i_me_range; Integer pixel motion estimation search range (from predicted mv)
|
||||
int i_mv_range; Maximum length of motion vector (in pixels). -1 = auto, based on level
|
||||
int i_mv_range_thread; Minimum space between threads. -1 = auto, based on number of threads.
|
||||
int i_subpel_refine; Sub-pixel motion estimation quality
|
||||
int b_chroma_me; Sub-pixel chroma motion estimation and mode selection for P frames
|
||||
int b_mixed_references; Allow each macroblock partition in the P frame to have its own reference number
|
||||
int i_trellis; Trellis quantization, find the appropriate quantization value for each 8x8 block, requires CABAC, default 0 0: off 1: use only at the end of encoding 2: always use
|
||||
int b_fast_pskip; Fast P frame skip detection
|
||||
int b_dct_decimate; Transform parameter domain in P-frames
|
||||
int i_noise_reduction; Adaptive pseudo-blind area
|
||||
float f_psy_rd; Psy RD strength
|
||||
float f_psy_trellis; Psy trellis strength
|
||||
int b_psy; Toggle all psy optimizations
|
||||
|
||||
, the size of the invalid area used in luminance quantization
|
||||
int i_luma_deadzone[2]; {Inter-frame, Intra-frame}
|
||||
|
||||
int b_psnr; Calculate and print PSNR information
|
||||
int b_ssim; Calculate and print SSIM information
|
||||
} analyse;
|
||||
|
||||
Bitrate control parameters
|
||||
struct
|
||||
{
|
||||
int i_rc_method; X264_RC_*
|
||||
|
||||
int i_qp_constant; 0-51
|
||||
int i_qp_min; Minimum quantization value allowed
|
||||
int i_qp_max; Maximum quantization value allowed
|
||||
int i_qp_step; Maximum quantization step between frames
|
||||
|
||||
int i_bitrate; Set average bitrate
|
||||
float f_rf_constant; 1pass VBR, nominal QP
|
||||
float f_rate_tolerance;
|
||||
int i_vbv_max_bitrate; In average bitrate mode, the maximum instantaneous bitrate, default 0 (same as -B setting)
|
||||
int i_vbv_buffer_size; Size of the bitrate control buffer, unit kbit, default 0
|
||||
float f_vbv_buffer_init; <=1: fraction of buffer_size. >1: kbit bitrate control buffer data retention maximum data amount ratio to buffer size, range 0~1.0, default 0.9
|
||||
float f_ip_factor;
|
||||
float f_pb_factor;
|
||||
|
||||
int i_aq_mode; psy adaptive QP. (X264_AQ_*)
|
||||
float f_aq_strength;
|
||||
int b_mb_tree; Macroblock-tree ratecontrol.
|
||||
int i_lookahead;
|
||||
|
||||
2pass multiple compression bitrate control
|
||||
int b_stat_write; Enable stat writing in psz_stat_out
|
||||
char *psz_stat_out;
|
||||
int b_stat_read; Read stat from psz_stat_in and use it
|
||||
char *psz_stat_in;
|
||||
|
||||
2pass params (same as ffmpeg ones)
|
||||
float f_qcompress; 0.0 => cbr, 1.0 => constant qp
|
||||
float f_qblur; Quantization blur over time
|
||||
float f_complexity_blur; Complexity blur over time
|
||||
x264_zone_t *zones; Bitrate control coverage
|
||||
int i_zones; number of zone_t's
|
||||
char *psz_zones; Another way to specify the zone
|
||||
} rc;
|
||||
|
||||
Muxing parameters
|
||||
int b_aud; Generate access unit delimiter
|
||||
int b_repeat_headers; Place SPS/PPS before each keyframe
|
||||
int i_sps_id; SPS and PPS id number
|
||||
|
||||
Slice (like strip) parameters
|
||||
int i_slice_max_size; Maximum number of bytes per slice, including expected NAL overhead.
|
||||
int i_slice_max_mbs; Maximum number of macroblocks per slice, overwrite i_slice_count
|
||||
int i_slice_count; Number of strips per frame: Set rectangular strips.
|
||||
|
||||
Optional callback for freeing this x264_param_t when it is done being used.
|
||||
* Only used when the x264_param_t sits in memory for an indefinite period of time,
|
||||
* i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones.
|
||||
* Not used when x264_encoder_reconfig is called directly.
|
||||
void (*param_free)( void* );
|
||||
} x264_param_t;
|
||||
* [AUTO-TRANSLATED:b730fe72]
|
||||
} x264_param_t;*/
|
||||
|
||||
bool H264Encoder::init(int iWidth, int iHeight, int iFps, int iBitRate) {
|
||||
@ -213,8 +387,10 @@ bool H264Encoder::init(int iWidth, int iHeight, int iFps, int iBitRate) {
|
||||
return true;
|
||||
}
|
||||
x264_param_t X264Param, *pX264Param = &X264Param;
|
||||
//* 配置参数
|
||||
//* 使用默认参数
|
||||
// * 配置参数 [AUTO-TRANSLATED:1629898c]
|
||||
// * Configure parameters
|
||||
// * 使用默认参数 [AUTO-TRANSLATED:db7658e2]
|
||||
// * Use default parameters
|
||||
x264_param_default_preset(pX264Param, "ultrafast", "zerolatency");
|
||||
|
||||
//* cpuFlags
|
||||
@ -233,13 +409,18 @@ bool H264Encoder::init(int iWidth, int iHeight, int iFps, int iBitRate) {
|
||||
pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定
|
||||
pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径
|
||||
pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。
|
||||
//该值不影响解码的速度,但是越大解码
|
||||
//所需的内存越大。这个值在一般情况下
|
||||
//越大效果越好,但是超过6以后效果就
|
||||
//不明显了。
|
||||
// 该值不影响解码的速度,但是越大解码 [AUTO-TRANSLATED:23eb12ae]
|
||||
// This value does not affect the decoding speed, but the larger the decoding
|
||||
// 所需的内存越大。这个值在一般情况下 [AUTO-TRANSLATED:3ff4f036]
|
||||
// The more memory required. This value is generally
|
||||
// 越大效果越好,但是超过6以后效果就 [AUTO-TRANSLATED:3252f33a]
|
||||
// The better the effect, but the effect is not obvious after 6
|
||||
// 不明显了。 [AUTO-TRANSLATED:d654ba67]
|
||||
// It's not obvious.
|
||||
|
||||
pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis
|
||||
//pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式
|
||||
// pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式 [AUTO-TRANSLATED:24c6240d]
|
||||
// pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO Motion detection method
|
||||
pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur
|
||||
|
||||
//* bitstream parameters
|
||||
@ -262,6 +443,27 @@ bool H264Encoder::init(int iWidth, int iHeight, int iFps, int iBitRate) {
|
||||
如果一个GOP的最后一帧(上例中是第5帧)设置为B帧,
|
||||
这个码流就是open-GOP,设置为P帧就是close-GOP。
|
||||
由于B帧压缩性能好于P帧,因此open-GOP在编码性能上稍微优于close-GOP,
|
||||
/*open-GOP
|
||||
open-GOP only appears when the bitstream contains B frames.
|
||||
A frame in a GOP needs to rely on some frames in the previous GOP when decoding,
|
||||
This GOP is called open-GOP.
|
||||
Some decoders do not fully support open-GOP bitstreams,
|
||||
For example, Blu-ray decoders, so open-GOP is disabled by default in x264.
|
||||
For the decoding end, if the received bitstream is as follows: I0 B0 B1 P0 B2 B3... This is an open-GOP bitstream (I frame followed by B frame).
|
||||
Therefore, the decoding of B0 B1 needs to use the data of the GOP before I0, and the dts of B0 B1 is less than that of I0.
|
||||
If the bitstream is as follows: I0 P0 B0 B1 P1 B2 B3... This is a close-GOP bitstream,
|
||||
The decoding of all frames after I0 does not depend on the frames before I0, and the dts of all frames after I0 is greater than that of I0.
|
||||
If the bitstream is IDR0 B0 B1 P0 B2 B3... then this GOP is close-GOP, although the dst of B0, B1 is smaller than that of IDR0,
|
||||
But both the encoder and decoder refresh the reference buffer, B0, B1 cannot refer to the forward GOP frame.
|
||||
For the encoding end, if the encoding frame type is determined as follows: ...P0 B1 B2 P3 B4 B5 I6 This will output an open-Gop bitstream (P0 P3 B1 B2 I6 B4 B5...),
|
||||
The decoding of B4 B5 depends on P3.
|
||||
If the encoding frame type is determined as follows...P0 B1 B2 P3 B4 P5 I6, then this will not output an open-GOP bitstream (P0 P3 B1 B2 P5 B4 I6...).
|
||||
The difference between the two is whether the 5th frame before I6 is set to B frame or P frame,
|
||||
If the last frame of a GOP (the 5th frame in the example above) is set to B frame,
|
||||
This bitstream is open-GOP, and setting it to P frame is close-GOP.
|
||||
Since B frames have better compression performance than P frames, open-GOP performs slightly better than close-GOP in terms of encoding performance,
|
||||
But for compatibility and less trouble, it's better to turn off opne-GOP.
|
||||
* [AUTO-TRANSLATED:6ccfc922]
|
||||
但为了兼容性和少一些麻烦,还是把opne-GOP关闭的好。*/
|
||||
pX264Param->b_open_gop = 0;
|
||||
pX264Param->i_bframe = 0; //最大B帧数.
|
||||
@ -282,11 +484,14 @@ bool H264Encoder::init(int iWidth, int iHeight, int iFps, int iBitRate) {
|
||||
pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度
|
||||
pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧,0 否 1,放
|
||||
|
||||
//* 设置Profile.使用baseline
|
||||
// * 设置Profile.使用baseline [AUTO-TRANSLATED:c451b8a5]
|
||||
// * Set Profile. Use baseline
|
||||
x264_param_apply_profile(pX264Param, "high");
|
||||
|
||||
//* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264
|
||||
//* 的参数.通过x264_encoder_reconfig更新X264的参数
|
||||
// * 打开编码器句柄,通过x264_encoder_parameters得到设置给X264 [AUTO-TRANSLATED:e52faa11]
|
||||
// * Open encoder handle, get the settings for X264 through x264_encoder_parameters
|
||||
// * 的参数.通过x264_encoder_reconfig更新X264的参数 [AUTO-TRANSLATED:83b929df]
|
||||
// * Parameters. Update the parameters of X264 through x264_encoder_reconfig
|
||||
_pX264Handle = x264_encoder_open(pX264Param);
|
||||
if (!_pX264Handle) {
|
||||
return false;
|
||||
|
@ -88,7 +88,8 @@ static bool checkIfSupportedNvidia_l() {
|
||||
bool find_driver = false;
|
||||
File::scanDir("/dev", [&](const string &path, bool is_dir) {
|
||||
if (!is_dir && start_with(path, "/dev/nvidia")) {
|
||||
//找到nvidia的驱动
|
||||
// 找到nvidia的驱动 [AUTO-TRANSLATED:5b87bf81]
|
||||
// Find the Nvidia driver
|
||||
find_driver = true;
|
||||
return false;
|
||||
}
|
||||
@ -403,7 +404,8 @@ FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num, const std:
|
||||
throw std::runtime_error("创建解码器失败");
|
||||
}
|
||||
|
||||
//保存AVFrame的引用
|
||||
// 保存AVFrame的引用 [AUTO-TRANSLATED:2df53d07]
|
||||
// Save the AVFrame reference
|
||||
#ifdef FF_API_OLD_ENCDEC
|
||||
_context->refcounted_frames = 1;
|
||||
#endif
|
||||
@ -441,7 +443,8 @@ FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num, const std:
|
||||
_context->flags |= AV_CODEC_FLAG_TRUNCATED;
|
||||
_do_merger = false;
|
||||
} else {
|
||||
// 此时业务层应该需要合帧
|
||||
// 此时业务层应该需要合帧 [AUTO-TRANSLATED:8dea0fff]
|
||||
// The business layer should need to merge frames at this time
|
||||
_do_merger = true;
|
||||
}
|
||||
#endif
|
||||
@ -449,13 +452,15 @@ FFmpegDecoder::FFmpegDecoder(const Track::Ptr &track, int thread_num, const std:
|
||||
int ret = avcodec_open2(_context.get(), codec, &dict);
|
||||
av_dict_free(&dict);
|
||||
if (ret >= 0) {
|
||||
//成功
|
||||
// 成功 [AUTO-TRANSLATED:7d878ca9]
|
||||
// Success
|
||||
InfoL << "打开解码器成功:" << codec->name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (codec_default && codec_default != codec) {
|
||||
//硬件编解码器打开失败,尝试软件的
|
||||
// 硬件编解码器打开失败,尝试软件的 [AUTO-TRANSLATED:060200f4]
|
||||
// Hardware codec failed to open, try software codec
|
||||
WarnL << "打开解码器" << codec->name << "失败,原因是:" << ffmpeg_err(ret) << ", 再尝试打开解码器" << codec_default->name;
|
||||
codec = codec_default;
|
||||
continue;
|
||||
@ -507,7 +512,8 @@ bool FFmpegDecoder::inputFrame_l(const Frame::Ptr &frame, bool live, bool enable
|
||||
|
||||
bool FFmpegDecoder::inputFrame(const Frame::Ptr &frame, bool live, bool async, bool enable_merge) {
|
||||
if (async && !TaskManager::isEnabled() && getContext()->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
//开启异步编码,且为视频,尝试启动异步解码线程
|
||||
// 开启异步编码,且为视频,尝试启动异步解码线程 [AUTO-TRANSLATED:17a68fc6]
|
||||
// Enable asynchronous encoding, and it is video, try to start asynchronous decoding thread
|
||||
startThread("decoder thread");
|
||||
}
|
||||
|
||||
@ -518,7 +524,8 @@ bool FFmpegDecoder::inputFrame(const Frame::Ptr &frame, bool live, bool async, b
|
||||
auto frame_cache = Frame::getCacheAbleFrame(frame);
|
||||
return addDecodeTask(frame->keyFrame(), [this, live, frame_cache, enable_merge]() {
|
||||
inputFrame_l(frame_cache, live, enable_merge);
|
||||
//此处模拟解码太慢导致的主动丢帧
|
||||
// 此处模拟解码太慢导致的主动丢帧 [AUTO-TRANSLATED:fc8bea8a]
|
||||
// Here simulates decoding too slow, resulting in active frame dropping
|
||||
//usleep(100 * 1000);
|
||||
});
|
||||
}
|
||||
@ -554,7 +561,8 @@ bool FFmpegDecoder::decodeFrame(const char *data, size_t size, uint64_t dts, uin
|
||||
break;
|
||||
}
|
||||
if (live && pts - out_frame->get()->pts > MAX_DELAY_SECOND * 1000 && _ticker.createdTime() > 10 * 1000) {
|
||||
//后面的帧才忽略,防止Track无法ready
|
||||
// 后面的帧才忽略,防止Track无法ready [AUTO-TRANSLATED:23f1a7c9]
|
||||
// The following frames are ignored to prevent the Track from being ready
|
||||
WarnL << "解码时,忽略" << MAX_DELAY_SECOND << "秒前的数据:" << pts << " " << out_frame->get()->pts;
|
||||
continue;
|
||||
}
|
||||
@ -593,7 +601,8 @@ FFmpegFrame::Ptr FFmpegSwr::inputFrame(const FFmpegFrame::Ptr &frame) {
|
||||
frame->get()->channels == _target_channels &&
|
||||
frame->get()->channel_layout == (uint64_t)_target_channel_layout &&
|
||||
frame->get()->sample_rate == _target_samplerate) {
|
||||
//不转格式
|
||||
// 不转格式 [AUTO-TRANSLATED:31dc6ae1]
|
||||
// Do not convert format
|
||||
return frame;
|
||||
}
|
||||
if (!_ctx) {
|
||||
@ -655,11 +664,13 @@ FFmpegFrame::Ptr FFmpegSws::inputFrame(const FFmpegFrame::Ptr &frame, int &ret,
|
||||
auto target_width = _target_width ? _target_width : frame->get()->width;
|
||||
auto target_height = _target_height ? _target_height : frame->get()->height;
|
||||
if (frame->get()->format == _target_format && frame->get()->width == target_width && frame->get()->height == target_height) {
|
||||
//不转格式
|
||||
// 不转格式 [AUTO-TRANSLATED:31dc6ae1]
|
||||
// Do not convert format
|
||||
return frame;
|
||||
}
|
||||
if (_ctx && (_src_width != frame->get()->width || _src_height != frame->get()->height || _src_format != (enum AVPixelFormat) frame->get()->format)) {
|
||||
//输入分辨率发生变化了
|
||||
// 输入分辨率发生变化了 [AUTO-TRANSLATED:0e4ea2e8]
|
||||
// Input resolution has changed
|
||||
sws_freeContext(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
@ -103,16 +103,19 @@ bool DevChannel::inputAAC(const char *data_without_adts, int len, uint64_t dts,
|
||||
}
|
||||
|
||||
if (!adts_header) {
|
||||
//没有adts头
|
||||
// 没有adts头 [AUTO-TRANSLATED:b9faaa83]
|
||||
// No adts header
|
||||
return inputFrame(std::make_shared<FrameFromPtr>(CodecAAC, (char *) data_without_adts, len, dts, 0, 0));
|
||||
}
|
||||
|
||||
if (adts_header + ADTS_HEADER_LEN == data_without_adts) {
|
||||
//adts头和帧在一起
|
||||
// adts头和帧在一起 [AUTO-TRANSLATED:76c4e678]
|
||||
// adts header and frame together
|
||||
return inputFrame(std::make_shared<FrameFromPtr>(CodecAAC, (char *) data_without_adts - ADTS_HEADER_LEN, len + ADTS_HEADER_LEN, dts, 0, ADTS_HEADER_LEN));
|
||||
}
|
||||
|
||||
//adts头和帧不在一起
|
||||
// adts头和帧不在一起 [AUTO-TRANSLATED:591dd07a]
|
||||
// adts header and frame not together
|
||||
char *data_with_adts = new char[len + ADTS_HEADER_LEN];
|
||||
memcpy(data_with_adts, adts_header, ADTS_HEADER_LEN);
|
||||
memcpy(data_with_adts + ADTS_HEADER_LEN, data_without_adts, len);
|
||||
|
@ -41,12 +41,16 @@ public:
|
||||
|
||||
/**
|
||||
* MultiMediaSourceMuxer类的包装,方便初学者使用
|
||||
* Wrapper class for MultiMediaSourceMuxer, making it easier for beginners to use.
|
||||
|
||||
* [AUTO-TRANSLATED:101887bd]
|
||||
*/
|
||||
class DevChannel : public MultiMediaSourceMuxer{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<DevChannel>;
|
||||
|
||||
//fDuration<=0为直播,否则为点播
|
||||
// fDuration<=0为直播,否则为点播 [AUTO-TRANSLATED:e3b6029a]
|
||||
// fDuration<=0 for live streaming, otherwise for on-demand
|
||||
DevChannel(const MediaTuple& tuple, float duration = 0, const ProtocolOption &option = ProtocolOption())
|
||||
: MultiMediaSourceMuxer(tuple, duration, option) {}
|
||||
|
||||
@ -54,6 +58,11 @@ public:
|
||||
* 初始化视频Track
|
||||
* 相当于MultiMediaSourceMuxer::addTrack(VideoTrack::Ptr );
|
||||
* @param info 视频相关信息
|
||||
* Initialize the video Track
|
||||
* Equivalent to MultiMediaSourceMuxer::addTrack(VideoTrack::Ptr );
|
||||
* @param info Video related information
|
||||
|
||||
* [AUTO-TRANSLATED:6845d52d]
|
||||
*/
|
||||
bool initVideo(const VideoInfo &info);
|
||||
|
||||
@ -61,6 +70,11 @@ public:
|
||||
* 初始化音频Track
|
||||
* 相当于MultiMediaSourceMuxer::addTrack(AudioTrack::Ptr );
|
||||
* @param info 音频相关信息
|
||||
* Initialize the audio Track
|
||||
* Equivalent to MultiMediaSourceMuxer::addTrack(AudioTrack::Ptr );
|
||||
* @param info Audio related information
|
||||
|
||||
* [AUTO-TRANSLATED:5be9d272]
|
||||
*/
|
||||
bool initAudio(const AudioInfo &info);
|
||||
|
||||
@ -70,6 +84,13 @@ public:
|
||||
* @param len 数据指针长度
|
||||
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
|
||||
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
|
||||
* Input 264 frame
|
||||
* @param data 264 single frame data pointer
|
||||
* @param len Data pointer length
|
||||
* @param dts Decode timestamp, in milliseconds; If it is 0, the timestamp will be generated automatically internally
|
||||
* @param pts Play timestamp, in milliseconds; If it is 0, it will be assigned to dts internally
|
||||
|
||||
* [AUTO-TRANSLATED:bda112e9]
|
||||
*/
|
||||
bool inputH264(const char *data, int len, uint64_t dts, uint64_t pts = 0);
|
||||
|
||||
@ -79,6 +100,13 @@ public:
|
||||
* @param len 数据指针长度
|
||||
* @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳
|
||||
* @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts
|
||||
* Input 265 frame
|
||||
* @param data 265 single frame data pointer
|
||||
* @param len Data pointer length
|
||||
* @param dts Decode timestamp, in milliseconds; If it is 0, the timestamp will be generated automatically internally
|
||||
* @param pts Play timestamp, in milliseconds; If it is 0, it will be assigned to dts internally
|
||||
|
||||
* [AUTO-TRANSLATED:1fc1c892]
|
||||
*/
|
||||
bool inputH265(const char *data, int len, uint64_t dts, uint64_t pts = 0);
|
||||
|
||||
@ -88,6 +116,13 @@ public:
|
||||
* @param len 帧数据长度
|
||||
* @param dts 时间戳,单位毫秒
|
||||
* @param adts_header adts头
|
||||
* Input aac frame
|
||||
* @param data_without_adts aac frame without adts header
|
||||
* @param len Frame data length
|
||||
* @param dts Timestamp, in milliseconds
|
||||
* @param adts_header adts header
|
||||
|
||||
* [AUTO-TRANSLATED:6eca0279]
|
||||
*/
|
||||
bool inputAAC(const char *data_without_adts, int len, uint64_t dts, const char *adts_header);
|
||||
|
||||
@ -96,6 +131,12 @@ public:
|
||||
* @param data 音频帧
|
||||
* @param len 帧数据长度
|
||||
* @param dts 时间戳,单位毫秒
|
||||
* Input OPUS/G711 audio frame
|
||||
* @param data Audio frame
|
||||
* @param len Frame data length
|
||||
* @param dts Timestamp, in milliseconds
|
||||
|
||||
* [AUTO-TRANSLATED:5f13cdf6]
|
||||
*/
|
||||
bool inputAudio(const char *data, int len, uint64_t dts);
|
||||
|
||||
@ -104,6 +145,12 @@ public:
|
||||
* @param yuv yuv420p数据指针
|
||||
* @param linesize yuv420p数据linesize
|
||||
* @param cts 采集时间戳,单位毫秒
|
||||
* Input yuv420p video frame, encoding will be completed internally and inputH264 method will be called
|
||||
* @param yuv yuv420p data pointer
|
||||
* @param linesize yuv420p data linesize
|
||||
* @param cts Capture timestamp, in milliseconds
|
||||
|
||||
* [AUTO-TRANSLATED:1b945575]
|
||||
*/
|
||||
bool inputYUV(char *yuv[3], int linesize[3], uint64_t cts);
|
||||
|
||||
@ -112,10 +159,17 @@ public:
|
||||
* @param data pcm数据指针,int16整形
|
||||
* @param len pcm数据长度
|
||||
* @param cts 采集时间戳,单位毫秒
|
||||
* Input pcm data, encoding will be completed internally and inputAAC method will be called
|
||||
* @param data pcm data pointer, int16 integer
|
||||
* @param len pcm data length
|
||||
* @param cts Capture timestamp, in milliseconds
|
||||
|
||||
* [AUTO-TRANSLATED:b99a9e82]
|
||||
*/
|
||||
bool inputPCM(char *data, int len, uint64_t cts);
|
||||
|
||||
//// 重载基类方法,确保线程安全 ////
|
||||
// // 重载基类方法,确保线程安全 //// [AUTO-TRANSLATED:86e2df12]
|
||||
// // Override base class methods to ensure thread safety ////
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
bool addTrack(const Track::Ptr & track) override;
|
||||
void addTrackCompleted() override;
|
||||
|
@ -24,9 +24,11 @@ bool MediaSink::addTrack(const Track::Ptr &track_in) {
|
||||
return false;
|
||||
}
|
||||
if (!_enable_audio) {
|
||||
// 关闭音频时,加快单视频流注册速度
|
||||
// 关闭音频时,加快单视频流注册速度 [AUTO-TRANSLATED:4d5a361d]
|
||||
// Speed up single video stream registration when audio is off
|
||||
if (track_in->getTrackType() == TrackAudio) {
|
||||
// 音频被全局忽略
|
||||
// 音频被全局忽略 [AUTO-TRANSLATED:a8134a0b]
|
||||
// Audio is globally ignored
|
||||
InfoL << "Audio disabled, audio track ignored";
|
||||
return false;
|
||||
}
|
||||
@ -35,7 +37,8 @@ bool MediaSink::addTrack(const Track::Ptr &track_in) {
|
||||
WarnL << "All track is ready, add track too late: " << track_in->getCodecName();
|
||||
return false;
|
||||
}
|
||||
// 克隆Track,只拷贝其数据,不拷贝其数据转发关系
|
||||
// 克隆Track,只拷贝其数据,不拷贝其数据转发关系 [AUTO-TRANSLATED:09edaa31]
|
||||
// Clone Track, only copy its data, not its data forwarding relationship
|
||||
auto track = track_in->clone();
|
||||
CHECK(track, "Clone track failed: ", track_in->getCodecName());
|
||||
auto index = track->getIndex();
|
||||
@ -55,11 +58,13 @@ bool MediaSink::addTrack(const Track::Ptr &track_in) {
|
||||
|
||||
GET_CONFIG(uint32_t, kMaxUnreadyFrame, General::kUnreadyFrameCache);
|
||||
if (frame_unread.size() > kMaxUnreadyFrame) {
|
||||
// 未就绪的的track,不能缓存太多的帧,否则可能内存溢出
|
||||
// 未就绪的的track,不能缓存太多的帧,否则可能内存溢出 [AUTO-TRANSLATED:23958376]
|
||||
// Unready tracks cannot cache too many frames, otherwise memory may overflow
|
||||
frame_unread.clear();
|
||||
WarnL << "Cached frame of unready track(" << frame->getCodecName() << ") is too much, now cleared";
|
||||
}
|
||||
// 还有Track未就绪,先缓存之
|
||||
// 还有Track未就绪,先缓存之 [AUTO-TRANSLATED:f96eadfa]
|
||||
// There are still unready tracks, cache them first
|
||||
frame_unread.emplace_back(Frame::getCacheAbleFrame(frame));
|
||||
return true;
|
||||
});
|
||||
@ -86,7 +91,8 @@ bool MediaSink::inputFrame(const Frame::Ptr &frame) {
|
||||
it->second.second = true;
|
||||
auto ret = it->second.first->inputFrame(frame);
|
||||
if (_mute_audio_maker && frame->getTrackType() == TrackVideo) {
|
||||
// 视频驱动产生静音音频
|
||||
// 视频驱动产生静音音频 [AUTO-TRANSLATED:2a8c789c]
|
||||
// Video driver generates silent audio
|
||||
_mute_audio_maker->inputFrame(frame);
|
||||
}
|
||||
checkTrackIfReady();
|
||||
@ -97,7 +103,8 @@ void MediaSink::checkTrackIfReady() {
|
||||
if (!_all_track_ready && !_track_ready_callback.empty()) {
|
||||
for (auto &pr : _track_map) {
|
||||
if (pr.second.second && pr.second.first->ready()) {
|
||||
// Track由未就绪状态转换成就绪状态,我们就触发onTrackReady回调
|
||||
// Track由未就绪状态转换成就绪状态,我们就触发onTrackReady回调 [AUTO-TRANSLATED:f8975e53]
|
||||
// When a Track transitions from an unready state to a ready state, we trigger the onTrackReady callback
|
||||
auto it = _track_ready_callback.find(pr.first);
|
||||
if (it != _track_ready_callback.end()) {
|
||||
it->second();
|
||||
@ -130,31 +137,36 @@ void MediaSink::checkTrackIfReady() {
|
||||
if (!_all_track_ready) {
|
||||
GET_CONFIG(uint32_t, kMaxWaitReadyMS, General::kWaitTrackReadyMS);
|
||||
if (_ticker.elapsedTime() > kMaxWaitReadyMS) {
|
||||
// 如果超过规定时间,那么不再等待并忽略未准备好的Track
|
||||
// 如果超过规定时间,那么不再等待并忽略未准备好的Track [AUTO-TRANSLATED:fd089806]
|
||||
// If it exceeds the specified time, then stop waiting and ignore unprepared Tracks
|
||||
emitAllTrackReady();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_track_ready_callback.empty()) {
|
||||
// 在超时时间内,如果存在未准备好的Track,那么继续等待
|
||||
// 在超时时间内,如果存在未准备好的Track,那么继续等待 [AUTO-TRANSLATED:cfaf3b49]
|
||||
// Within the timeout period, if there are unprepared Tracks, then continue waiting
|
||||
return;
|
||||
}
|
||||
|
||||
if (_only_audio && _audio_add) {
|
||||
// 只开启音频
|
||||
// 只开启音频 [AUTO-TRANSLATED:bac07e47]
|
||||
// Only enable audio
|
||||
emitAllTrackReady();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_track_map.size() == _max_track_size) {
|
||||
// 如果已经添加了音视频Track,并且不存在未准备好的Track,那么说明所有Track都准备好了
|
||||
// 如果已经添加了音视频Track,并且不存在未准备好的Track,那么说明所有Track都准备好了 [AUTO-TRANSLATED:6fce8779]
|
||||
// If audio and video Tracks have been added, and there are no unprepared Tracks, then all Tracks are ready
|
||||
emitAllTrackReady();
|
||||
return;
|
||||
}
|
||||
|
||||
GET_CONFIG(uint32_t, kMaxAddTrackMS, General::kWaitAddTrackMS);
|
||||
if (_track_map.size() == 1 && (_ticker.elapsedTime() > kMaxAddTrackMS || !_enable_audio)) {
|
||||
// 如果只有一个Track,那么在该Track添加后,我们最多还等待若干时间(可能后面还会添加Track)
|
||||
// 如果只有一个Track,那么在该Track添加后,我们最多还等待若干时间(可能后面还会添加Track) [AUTO-TRANSLATED:5b4bd438]
|
||||
// If there is only one Track, then after the Track is added, we wait for a certain amount of time at most (more Tracks may be added later)
|
||||
emitAllTrackReady();
|
||||
return;
|
||||
}
|
||||
@ -181,9 +193,11 @@ void MediaSink::emitAllTrackReady() {
|
||||
|
||||
DebugL << "All track ready use " << _ticker.elapsedTime() << "ms";
|
||||
if (!_track_ready_callback.empty()) {
|
||||
// 这是超时强制忽略未准备好的Track
|
||||
// 这是超时强制忽略未准备好的Track [AUTO-TRANSLATED:d4f57e00]
|
||||
// This is a timeout forced ignore of unprepared Tracks
|
||||
_track_ready_callback.clear();
|
||||
// 移除未准备好的Track
|
||||
// 移除未准备好的Track [AUTO-TRANSLATED:69965c62]
|
||||
// Remove unprepared Tracks
|
||||
for (auto it = _track_map.begin(); it != _track_map.end();) {
|
||||
if (!it->second.second || !it->second.first->ready()) {
|
||||
WarnL << "Track not ready for a long time, ignored: " << it->second.first->getCodecName();
|
||||
@ -195,13 +209,16 @@ void MediaSink::emitAllTrackReady() {
|
||||
}
|
||||
|
||||
if (!_track_map.empty()) {
|
||||
// 最少有一个有效的Track
|
||||
// 最少有一个有效的Track [AUTO-TRANSLATED:099adc94]
|
||||
// There is at least one valid Track
|
||||
onAllTrackReady_l();
|
||||
|
||||
// 全部Track就绪,我们一次性把之前的帧输出
|
||||
// 全部Track就绪,我们一次性把之前的帧输出 [AUTO-TRANSLATED:2431422b]
|
||||
// All Tracks are ready, we output all the previous frames at once
|
||||
for (auto &pr : _frame_unread) {
|
||||
if (_track_map.find(pr.first) == _track_map.end()) {
|
||||
// 该Track已经被移除
|
||||
// 该Track已经被移除 [AUTO-TRANSLATED:d44bf74e]
|
||||
// The Track has been removed
|
||||
continue;
|
||||
}
|
||||
pr.second.for_each([&](const Frame::Ptr &frame) { MediaSink::inputFrame(frame); });
|
||||
@ -213,7 +230,8 @@ void MediaSink::emitAllTrackReady() {
|
||||
}
|
||||
|
||||
void MediaSink::onAllTrackReady_l() {
|
||||
// 是否添加静音音频
|
||||
// 是否添加静音音频 [AUTO-TRANSLATED:bbfbfe73]
|
||||
// Whether to add silent audio
|
||||
if (_add_mute_audio) {
|
||||
addMuteAudioTrack();
|
||||
}
|
||||
@ -263,11 +281,13 @@ static uint8_t ADTS_CONFIG[2] = { 0x15, 0x88 };
|
||||
|
||||
bool MuteAudioMaker::inputFrame(const Frame::Ptr &frame) {
|
||||
if (_track_index == -1) {
|
||||
// 锁定track
|
||||
// 锁定track [AUTO-TRANSLATED:41aff35e]
|
||||
// Lock track
|
||||
_track_index = frame->getIndex();
|
||||
}
|
||||
if (frame->getIndex() != _track_index) {
|
||||
// 不是锁定的track
|
||||
// 不是锁定的track [AUTO-TRANSLATED:496bd08b]
|
||||
// Not a locked track
|
||||
return false;
|
||||
}
|
||||
auto audio_idx = frame->dts() / MUTE_ADTS_DATA_MS;
|
||||
|
@ -27,16 +27,27 @@ public:
|
||||
* 添加track,内部会调用Track的clone方法
|
||||
* 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系
|
||||
* @param track
|
||||
* Add track, internally calls the clone method of Track
|
||||
* Only clones sps pps information, not the Delegate relationship
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:ba6faf58]
|
||||
*/
|
||||
virtual bool addTrack(const Track::Ptr & track) = 0;
|
||||
|
||||
/**
|
||||
* 添加track完毕
|
||||
* Track added
|
||||
|
||||
* [AUTO-TRANSLATED:dc70ddea]
|
||||
*/
|
||||
virtual void addTrackCompleted() {};
|
||||
|
||||
/**
|
||||
* 重置track
|
||||
* Reset track
|
||||
|
||||
* [AUTO-TRANSLATED:95dc0b4f]
|
||||
*/
|
||||
virtual void resetTracks() {};
|
||||
};
|
||||
@ -48,6 +59,9 @@ public:
|
||||
|
||||
/**
|
||||
* aac静音音频添加器
|
||||
* AAC mute audio adder
|
||||
|
||||
* [AUTO-TRANSLATED:aa154f71]
|
||||
*/
|
||||
class MuteAudioMaker : public FrameDispatcher {
|
||||
public:
|
||||
@ -62,6 +76,10 @@ private:
|
||||
/**
|
||||
* 该类的作用是等待Track ready()返回true也就是就绪后再通知派生类进行下一步的操作
|
||||
* 目的是输入Frame前由Track截取处理下,以便获取有效的信息(譬如sps pps aa_cfg)
|
||||
* The role of this class is to wait for Track ready() to return true, that is, ready, and then notify the derived class to perform the next operation.
|
||||
* The purpose is to intercept and process the input Frame by Track before inputting the Frame, so as to obtain valid information (such as sps pps aa_cfg)
|
||||
|
||||
* [AUTO-TRANSLATED:9e4f096b]
|
||||
*/
|
||||
class MediaSink : public MediaSinkInterface, public TrackSource{
|
||||
public:
|
||||
@ -69,6 +87,10 @@ public:
|
||||
/**
|
||||
* 输入frame
|
||||
* @param frame
|
||||
* Input frame
|
||||
* @param frame
|
||||
|
||||
* [AUTO-TRANSLATED:7aaa5bba]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
@ -76,6 +98,11 @@ public:
|
||||
* 添加track,内部会调用Track的clone方法
|
||||
* 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系
|
||||
* @param track
|
||||
* Add track, internally calls the clone method of Track
|
||||
* Only clones sps pps information, not the Delegate relationship
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:ba6faf58]
|
||||
*/
|
||||
bool addTrack(const Track::Ptr & track) override;
|
||||
|
||||
@ -83,48 +110,79 @@ public:
|
||||
* 添加Track完毕,如果是单Track,会最多等待3秒才会触发onAllTrackReady
|
||||
* 这样会增加生成流的延时,如果添加了音视频双Track,那么可以不调用此方法
|
||||
* 否则为了降低流注册延时,请手动调用此方法
|
||||
* Track added, if it is a single Track, it will wait for a maximum of 3 seconds before triggering onAllTrackReady
|
||||
* This will increase the delay in generating the stream. If you add both audio and video tracks, you can skip this method.
|
||||
* Otherwise, to reduce the stream registration delay, please call this method manually.
|
||||
|
||||
* [AUTO-TRANSLATED:580b6163]
|
||||
*/
|
||||
void addTrackCompleted() override;
|
||||
|
||||
/**
|
||||
* 设置最大track数,取值范围>=1;该方法与addTrackCompleted类型;
|
||||
* 在设置单track时,可以加快媒体注册速度
|
||||
* Set the maximum number of tracks, the value range is >=1; this method is of the addTrackCompleted type;
|
||||
* When setting a single track, it can speed up media registration
|
||||
|
||||
* [AUTO-TRANSLATED:cd521c6f]
|
||||
*/
|
||||
void setMaxTrackCount(size_t i);
|
||||
|
||||
/**
|
||||
* 重置track
|
||||
* Reset track
|
||||
|
||||
* [AUTO-TRANSLATED:95dc0b4f]
|
||||
*/
|
||||
void resetTracks() override;
|
||||
|
||||
/**
|
||||
* 获取所有Track
|
||||
* @param trackReady 是否获取已经准备好的Track
|
||||
* Get all Tracks
|
||||
* @param trackReady Whether to get the ready Track
|
||||
|
||||
* [AUTO-TRANSLATED:32032e47]
|
||||
*/
|
||||
std::vector<Track::Ptr> getTracks(bool trackReady = true) const override;
|
||||
|
||||
/**
|
||||
* 判断是否已经触发onAllTrackReady事件
|
||||
* Determine whether the onAllTrackReady event has been triggered
|
||||
|
||||
* [AUTO-TRANSLATED:fb8b4c71]
|
||||
*/
|
||||
bool isAllTrackReady() const;
|
||||
|
||||
/**
|
||||
* 设置是否开启音频
|
||||
* Set whether to enable audio
|
||||
|
||||
* [AUTO-TRANSLATED:0e9a3ef0]
|
||||
*/
|
||||
void enableAudio(bool flag);
|
||||
|
||||
/**
|
||||
* 设置单音频
|
||||
* Set single audio
|
||||
|
||||
* [AUTO-TRANSLATED:48fc734a]
|
||||
*/
|
||||
void setOnlyAudio();
|
||||
|
||||
/**
|
||||
* 设置是否开启添加静音音频
|
||||
* Set whether to enable adding mute audio
|
||||
|
||||
* [AUTO-TRANSLATED:49efef10]
|
||||
*/
|
||||
void enableMuteAudio(bool flag);
|
||||
|
||||
/**
|
||||
* 是否有视频track
|
||||
* Whether there is a video track
|
||||
|
||||
* [AUTO-TRANSLATED:4c4d651d]
|
||||
*/
|
||||
bool haveVideo() const;
|
||||
|
||||
@ -133,33 +191,54 @@ protected:
|
||||
* 某track已经准备好,其ready()状态返回true,
|
||||
* 此时代表可以获取其例如sps pps等相关信息了
|
||||
* @param track
|
||||
* A certain track is ready, its ready() status returns true,
|
||||
* This means that you can get its related information such as sps pps
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:720dedc1]
|
||||
*/
|
||||
virtual bool onTrackReady(const Track::Ptr & track) { return false; };
|
||||
|
||||
/**
|
||||
* 所有Track已经准备好,
|
||||
* All Tracks are ready,
|
||||
|
||||
* [AUTO-TRANSLATED:c54d02e2]
|
||||
*/
|
||||
virtual void onAllTrackReady() {};
|
||||
|
||||
/**
|
||||
* 某Track输出frame,在onAllTrackReady触发后才会调用此方法
|
||||
* @param frame
|
||||
* A certain Track outputs a frame, this method will be called only after onAllTrackReady is triggered
|
||||
* @param frame
|
||||
|
||||
* [AUTO-TRANSLATED:debbd247]
|
||||
*/
|
||||
virtual bool onTrackFrame(const Frame::Ptr &frame) { return false; };
|
||||
|
||||
private:
|
||||
/**
|
||||
* 触发onAllTrackReady事件
|
||||
* Trigger the onAllTrackReady event
|
||||
|
||||
* [AUTO-TRANSLATED:068fdb61]
|
||||
*/
|
||||
void emitAllTrackReady();
|
||||
|
||||
/**
|
||||
* 检查track是否准备完毕
|
||||
* Check if the track is ready
|
||||
|
||||
* [AUTO-TRANSLATED:12e7c3e6]
|
||||
*/
|
||||
void checkTrackIfReady();
|
||||
void onAllTrackReady_l();
|
||||
/**
|
||||
* 添加aac静音轨道
|
||||
* Add AAC mute track
|
||||
|
||||
* [AUTO-TRANSLATED:9ba052b5]
|
||||
*/
|
||||
bool addMuteAudioTrack();
|
||||
|
||||
@ -185,6 +264,9 @@ class MediaSinkDelegate : public MediaSink {
|
||||
public:
|
||||
/**
|
||||
* 设置track监听器
|
||||
* Set track listener
|
||||
|
||||
* [AUTO-TRANSLATED:cedc97d7]
|
||||
*/
|
||||
void setTrackListener(TrackListener *listener);
|
||||
|
||||
|
@ -95,11 +95,13 @@ MediaSource::~MediaSource() {
|
||||
|
||||
std::shared_ptr<void> MediaSource::getOwnership() {
|
||||
if (_owned.test_and_set()) {
|
||||
//已经被所有
|
||||
// 已经被所有 [AUTO-TRANSLATED:bab937dc]
|
||||
// Already owned by all
|
||||
return nullptr;
|
||||
}
|
||||
weak_ptr<MediaSource> weak_self = shared_from_this();
|
||||
//确保返回的Ownership智能指针不为空,0x01无实际意义
|
||||
// 确保返回的Ownership智能指针不为空,0x01无实际意义 [AUTO-TRANSLATED:9a4cca08]
|
||||
// Ensure that the returned Ownership smart pointer is not empty, 0x01 has no practical meaning
|
||||
return std::shared_ptr<void>((void *) 0x01, [weak_self](void *ptr) {
|
||||
auto strong_self = weak_self.lock();
|
||||
if (strong_self) {
|
||||
@ -116,7 +118,8 @@ int MediaSource::getBytesSpeed(TrackType type){
|
||||
}
|
||||
|
||||
uint64_t MediaSource::getAliveSecond() const {
|
||||
//使用Ticker对象获取存活时间的目的是防止修改系统时间导致回退
|
||||
// 使用Ticker对象获取存活时间的目的是防止修改系统时间导致回退 [AUTO-TRANSLATED:68474061]
|
||||
// The purpose of using the Ticker object to obtain the survival time is to prevent the modification of the system time from causing a rollback
|
||||
return _ticker.createdTime() / 1000;
|
||||
}
|
||||
|
||||
@ -202,7 +205,8 @@ bool MediaSource::close(bool force) {
|
||||
return false;
|
||||
}
|
||||
if (!force && totalReaderCount()) {
|
||||
//有人观看,不强制关闭
|
||||
// 有人观看,不强制关闭 [AUTO-TRANSLATED:44b7e24d]
|
||||
// Someone is watching, do not force close
|
||||
return false;
|
||||
}
|
||||
return listener->close(*this);
|
||||
@ -249,11 +253,14 @@ void MediaSource::onReaderChanged(int size) {
|
||||
}
|
||||
});
|
||||
} catch (MediaSourceEvent::NotImplemented &ex) {
|
||||
// 未实现接口,应该打印异常
|
||||
// 未实现接口,应该打印异常 [AUTO-TRANSLATED:84f28c9d]
|
||||
// The interface is not implemented, an exception should be printed
|
||||
WarnL << ex.what();
|
||||
} catch (...) {
|
||||
// getOwnerPoller()接口抛异常机制应该只对外不对内
|
||||
// 所以listener已经销毁导致获取归属线程失败的异常直接忽略
|
||||
// getOwnerPoller()接口抛异常机制应该只对外不对内 [AUTO-TRANSLATED:ee2e2923]
|
||||
// The getOwnerPoller() interface should only throw exceptions externally, not internally
|
||||
// 所以listener已经销毁导致获取归属线程失败的异常直接忽略 [AUTO-TRANSLATED:26cb5521]
|
||||
// Therefore, the exception that the listener has been destroyed and the ownership thread cannot be obtained is directly ignored
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +357,8 @@ static MediaSource::Ptr find_l(const string &schema, const string &vhost_in, con
|
||||
}
|
||||
|
||||
if (app.empty() || id.empty()) {
|
||||
//如果未指定app与stream id,那么就是遍历而非查找,所以应该返回查找失败
|
||||
// 如果未指定app与stream id,那么就是遍历而非查找,所以应该返回查找失败 [AUTO-TRANSLATED:84976471]
|
||||
// If no app and stream id are specified, then it is traversal instead of searching, so it should return search failure
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -358,8 +366,10 @@ static MediaSource::Ptr find_l(const string &schema, const string &vhost_in, con
|
||||
MediaSource::for_each_media([&](const MediaSource::Ptr &src) { ret = std::move(const_cast<MediaSource::Ptr &>(src)); }, schema, vhost, app, id);
|
||||
|
||||
if(!ret && from_mp4 && schema != HLS_SCHEMA){
|
||||
//未找到媒体源,则读取mp4创建一个
|
||||
//播放hls不触发mp4点播(因为HLS也可以用于录像,不是纯粹的直播)
|
||||
// 未找到媒体源,则读取mp4创建一个 [AUTO-TRANSLATED:e2e03a82]
|
||||
// If the media source is not found, read mp4 to create one
|
||||
// 播放hls不触发mp4点播(因为HLS也可以用于录像,不是纯粹的直播) [AUTO-TRANSLATED:30b18b6d]
|
||||
// Playing hls does not trigger mp4 on-demand (because HLS can also be used for recording, not purely live)
|
||||
ret = MediaSource::createFromMP4(schema, vhost, app, id);
|
||||
}
|
||||
return ret;
|
||||
@ -379,23 +389,27 @@ static void findAsync_l(const MediaInfo &info, const std::shared_ptr<Session> &s
|
||||
std::shared_ptr<atomic_flag> invoked(new atomic_flag{false});
|
||||
auto cb_once = [cb, invoked](const MediaSource::Ptr &src) {
|
||||
if (invoked->test_and_set()) {
|
||||
//回调已经执行过了
|
||||
// 回调已经执行过了 [AUTO-TRANSLATED:f034e2eb]
|
||||
// The callback has already been executed
|
||||
return;
|
||||
}
|
||||
cb(src);
|
||||
};
|
||||
|
||||
auto on_timeout = poller->doDelayTask(maxWaitMS, [cb_once, listener_tag]() {
|
||||
// 最多等待一定时间,如在这个时间内,流还未注册上,则返回空
|
||||
// 最多等待一定时间,如在这个时间内,流还未注册上,则返回空 [AUTO-TRANSLATED:e8851208]
|
||||
// Wait for a certain amount of time at most, if the stream is not registered within this time, return empty
|
||||
NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
|
||||
cb_once(nullptr);
|
||||
return 0;
|
||||
});
|
||||
|
||||
auto cancel_all = [on_timeout, listener_tag]() {
|
||||
//取消延时任务,防止多次回调
|
||||
// 取消延时任务,防止多次回调 [AUTO-TRANSLATED:42988b9c]
|
||||
// Cancel the delayed task to prevent multiple callbacks
|
||||
on_timeout->cancel();
|
||||
//取消媒体注册事件监听
|
||||
// 取消媒体注册事件监听 [AUTO-TRANSLATED:efb9aacb]
|
||||
// Cancel the media registration event listener
|
||||
NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
|
||||
};
|
||||
|
||||
@ -404,32 +418,38 @@ static void findAsync_l(const MediaInfo &info, const std::shared_ptr<Session> &s
|
||||
if (!bRegist ||
|
||||
sender.getSchema() != info.schema ||
|
||||
!equalMediaTuple(sender.getMediaTuple(), info)) {
|
||||
//不是自己感兴趣的事件,忽略之
|
||||
// 不是自己感兴趣的事件,忽略之 [AUTO-TRANSLATED:b4e102d4]
|
||||
// Not an event of interest, ignore it
|
||||
return;
|
||||
}
|
||||
|
||||
poller->async([weak_session, cancel_all, info, cb_once]() {
|
||||
cancel_all();
|
||||
if (auto strong_session = weak_session.lock()) {
|
||||
//播发器请求的流终于注册上了,切换到自己的线程再回复
|
||||
// 播发器请求的流终于注册上了,切换到自己的线程再回复 [AUTO-TRANSLATED:7b79ad9b]
|
||||
// The stream requested by the player is finally registered, switch to its own thread and reply
|
||||
DebugL << "收到媒体注册事件,回复播放器:" << info.getUrl();
|
||||
//再找一遍媒体源,一般能找到
|
||||
// 再找一遍媒体源,一般能找到 [AUTO-TRANSLATED:069de7f6]
|
||||
// Find the media source again, usually it can be found
|
||||
findAsync_l(info, strong_session, false, cb_once);
|
||||
}
|
||||
}, false);
|
||||
};
|
||||
|
||||
//监听媒体注册事件
|
||||
// 监听媒体注册事件 [AUTO-TRANSLATED:9cf13779]
|
||||
// Listen for media registration events
|
||||
NoticeCenter::Instance().addListener(listener_tag, Broadcast::kBroadcastMediaChanged, on_register);
|
||||
|
||||
function<void()> close_player = [cb_once, cancel_all, poller]() {
|
||||
poller->async([cancel_all, cb_once]() {
|
||||
cancel_all();
|
||||
//告诉播放器,流不存在,这样会立即断开播放器
|
||||
// 告诉播放器,流不存在,这样会立即断开播放器 [AUTO-TRANSLATED:b5b4eead]
|
||||
// Tell the player that the stream does not exist, so it will immediately disconnect the player
|
||||
cb_once(nullptr);
|
||||
});
|
||||
};
|
||||
//广播未找到流,此时可以立即去拉流,这样还来得及
|
||||
// 广播未找到流,此时可以立即去拉流,这样还来得及 [AUTO-TRANSLATED:794014f1]
|
||||
// Broadcast that the stream is not found, at this time you can immediately pull the stream, so it is still in time
|
||||
NOTICE_EMIT(BroadcastNotFoundStreamArgs, Broadcast::kBroadcastNotFoundStream, info, *session, close_player);
|
||||
}
|
||||
|
||||
@ -468,17 +488,20 @@ MediaSource::Ptr MediaSource::find(const string &vhost, const string &app, const
|
||||
void MediaSource::emitEvent(bool regist){
|
||||
auto listener = _listener.lock();
|
||||
if (listener) {
|
||||
//触发回调
|
||||
// 触发回调 [AUTO-TRANSLATED:08ea452d]
|
||||
// Trigger callback
|
||||
listener->onRegist(*this, regist);
|
||||
}
|
||||
//触发广播
|
||||
// 触发广播 [AUTO-TRANSLATED:a5b415a4]
|
||||
// Trigger broadcast
|
||||
NOTICE_EMIT(BroadcastMediaChangedArgs, Broadcast::kBroadcastMediaChanged, regist, *this);
|
||||
InfoL << (regist ? "媒体注册:" : "媒体注销:") << getUrl();
|
||||
}
|
||||
|
||||
void MediaSource::regist() {
|
||||
{
|
||||
//减小互斥锁临界区
|
||||
// 减小互斥锁临界区 [AUTO-TRANSLATED:1309d309]
|
||||
// Reduce mutex lock critical area
|
||||
lock_guard<recursive_mutex> lock(s_media_source_mtx);
|
||||
auto &ref = s_media_source_map[_schema][_tuple.vhost][_tuple.app][_tuple.stream];
|
||||
auto src = ref.lock();
|
||||
@ -486,7 +509,8 @@ void MediaSource::regist() {
|
||||
if (src.get() == this) {
|
||||
return;
|
||||
}
|
||||
//增加判断, 防止当前流已注册时再次注册
|
||||
// 增加判断, 防止当前流已注册时再次注册 [AUTO-TRANSLATED:ccc5dcb1]
|
||||
// Add judgment to prevent re-registration when the current stream is already registered
|
||||
throw std::invalid_argument("media source already existed:" + getUrl());
|
||||
}
|
||||
ref = shared_from_this();
|
||||
@ -509,7 +533,8 @@ static bool erase_media_source(bool &hit, const MediaSource *thiz, MAP &map, con
|
||||
if (it != map.end()) {
|
||||
auto src = it->second.lock();
|
||||
if (!src || src.get() == thiz) {
|
||||
//对象已经销毁或者对象就是自己,那么移除之
|
||||
// 对象已经销毁或者对象就是自己,那么移除之 [AUTO-TRANSLATED:1b9a11d1]
|
||||
// If the object has been destroyed or the object is itself, then remove it
|
||||
map.erase(it);
|
||||
hit = true;
|
||||
}
|
||||
@ -517,11 +542,13 @@ static bool erase_media_source(bool &hit, const MediaSource *thiz, MAP &map, con
|
||||
return map.empty();
|
||||
}
|
||||
|
||||
//反注册该源
|
||||
// 反注册该源 [AUTO-TRANSLATED:682c27ab]
|
||||
// Unregister the source
|
||||
bool MediaSource::unregist() {
|
||||
bool ret = false;
|
||||
{
|
||||
//减小互斥锁临界区
|
||||
// 减小互斥锁临界区 [AUTO-TRANSLATED:1309d309]
|
||||
// Reduce mutex lock critical area
|
||||
lock_guard<recursive_mutex> lock(s_media_source_mtx);
|
||||
erase_media_source(ret, this, s_media_source_map, _schema, _tuple.vhost, _tuple.app, _tuple.stream);
|
||||
}
|
||||
@ -557,7 +584,8 @@ void MediaInfo::parse(const std::string &url_in){
|
||||
splitUrl(split_vec[0], host, port);
|
||||
vhost = host;
|
||||
if (vhost == "localhost" || isIP(vhost.data())) {
|
||||
//如果访问的是localhost或ip,那么则为默认虚拟主机
|
||||
// 如果访问的是localhost或ip,那么则为默认虚拟主机 [AUTO-TRANSLATED:67291b7a]
|
||||
// If the access is to localhost or ip, then it is the default virtual host
|
||||
vhost = DEFAULT_VHOST;
|
||||
}
|
||||
}
|
||||
@ -583,7 +611,8 @@ void MediaInfo::parse(const std::string &url_in){
|
||||
|
||||
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
||||
if (!enableVhost || vhost.empty()) {
|
||||
//如果关闭虚拟主机或者虚拟主机为空,则设置虚拟主机为默认
|
||||
// 如果关闭虚拟主机或者虚拟主机为空,则设置虚拟主机为默认 [AUTO-TRANSLATED:9f76a112]
|
||||
// If the virtual host is closed or the virtual host is empty, set the virtual host to the default
|
||||
vhost = DEFAULT_VHOST;
|
||||
}
|
||||
}
|
||||
@ -617,41 +646,49 @@ void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){
|
||||
NOTICE_EMIT(BroadcastPlayerCountChangedArgs, Broadcast::kBroadcastPlayerCountChanged, sender.getMediaTuple(), sender.totalReaderCount());
|
||||
}
|
||||
if (size || sender.totalReaderCount()) {
|
||||
//还有人观看该视频,不触发关闭事件
|
||||
// 还有人观看该视频,不触发关闭事件 [AUTO-TRANSLATED:7f2f6ed3]
|
||||
// Someone is still watching this video, do not trigger the close event
|
||||
_async_close_timer = nullptr;
|
||||
return;
|
||||
}
|
||||
//没有任何人观看该视频源,表明该源可以关闭了
|
||||
// 没有任何人观看该视频源,表明该源可以关闭了 [AUTO-TRANSLATED:ea64bb8f]
|
||||
// No one is watching this video source, indicating that the source can be closed.
|
||||
GET_CONFIG(string, record_app, Record::kAppName);
|
||||
GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS);
|
||||
//如果mp4点播, 无人观看时我们强制关闭点播
|
||||
// 如果mp4点播, 无人观看时我们强制关闭点播 [AUTO-TRANSLATED:9576e4b0]
|
||||
// If it's an mp4 on-demand, we force close the on-demand when no one is watching.
|
||||
bool is_mp4_vod = sender.getMediaTuple().app == record_app;
|
||||
weak_ptr<MediaSource> weak_sender = sender.shared_from_this();
|
||||
|
||||
_async_close_timer = std::make_shared<Timer>(stream_none_reader_delay / 1000.0f, [weak_sender, is_mp4_vod]() {
|
||||
auto strong_sender = weak_sender.lock();
|
||||
if (!strong_sender) {
|
||||
//对象已经销毁
|
||||
// 对象已经销毁 [AUTO-TRANSLATED:130328af]
|
||||
// The object has been destroyed.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strong_sender->totalReaderCount()) {
|
||||
//还有人观看该视频,不触发关闭事件
|
||||
// 还有人观看该视频,不触发关闭事件 [AUTO-TRANSLATED:7f2f6ed3]
|
||||
// Someone is still watching this video, so the close event is not triggered.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_mp4_vod) {
|
||||
auto muxer = strong_sender->getMuxer();
|
||||
if (muxer && muxer->getOption().auto_close) {
|
||||
// 此流被标记为无人观看自动关闭流
|
||||
// 此流被标记为无人观看自动关闭流 [AUTO-TRANSLATED:64a0dac3]
|
||||
// This stream is marked as an automatically closed stream with no viewers.
|
||||
WarnL << "Auto cloe stream when none reader: " << strong_sender->getUrl();
|
||||
strong_sender->close(false);
|
||||
} else {
|
||||
// 直播时触发无人观看事件,让开发者自行选择是否关闭
|
||||
// 直播时触发无人观看事件,让开发者自行选择是否关闭 [AUTO-TRANSLATED:c6c75eaa]
|
||||
// When live streaming, trigger the no-viewer event, allowing developers to choose whether to close it.
|
||||
NOTICE_EMIT(BroadcastStreamNoneReaderArgs, Broadcast::kBroadcastStreamNoneReader, *strong_sender);
|
||||
}
|
||||
} else {
|
||||
//这个是mp4点播,我们自动关闭
|
||||
// 这个是mp4点播,我们自动关闭 [AUTO-TRANSLATED:8a7b9a90]
|
||||
// This is an mp4 on-demand, we automatically close it.
|
||||
WarnL << "MP4点播无人观看,自动关闭:" << strong_sender->getUrl();
|
||||
strong_sender->close(false);
|
||||
}
|
||||
@ -834,39 +871,47 @@ std::shared_ptr<MediaSourceEvent> MediaSourceEventInterceptor::getDelegate() con
|
||||
|
||||
static bool isFlushAble_default(bool is_video, uint64_t last_stamp, uint64_t new_stamp, size_t cache_size) {
|
||||
if (new_stamp + 500 < last_stamp) {
|
||||
//时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的
|
||||
// 时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的 [AUTO-TRANSLATED:67158987]
|
||||
// The timestamp rollback is relatively large (possibly during seek), because the timestamp in RTP is PTS, which may have a certain degree of rollback.
|
||||
return true;
|
||||
}
|
||||
|
||||
//时间戳发送变化或者缓存超过1024个,sendmsg接口一般最多只能发送1024个数据包
|
||||
// 时间戳发送变化或者缓存超过1024个,sendmsg接口一般最多只能发送1024个数据包 [AUTO-TRANSLATED:f87d1da0]
|
||||
// The timestamp sends changes or the cache exceeds 1024, the sendmsg interface generally can only send a maximum of 1024 data packets.
|
||||
return last_stamp != new_stamp || cache_size >= 1024;
|
||||
}
|
||||
|
||||
static bool isFlushAble_merge(bool is_video, uint64_t last_stamp, uint64_t new_stamp, size_t cache_size, int merge_ms) {
|
||||
if (new_stamp + 500 < last_stamp) {
|
||||
//时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的
|
||||
// 时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的 [AUTO-TRANSLATED:67158987]
|
||||
// The timestamp rollback is relatively large (possibly during seek), because the timestamp in RTP is PTS, which may have a certain degree of rollback.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new_stamp > last_stamp + merge_ms) {
|
||||
//时间戳增量超过合并写阈值
|
||||
// 时间戳增量超过合并写阈值 [AUTO-TRANSLATED:cbcf3ab0]
|
||||
// The timestamp increment exceeds the merge write threshold.
|
||||
return true;
|
||||
}
|
||||
|
||||
//缓存数超过1024个,这个逻辑用于避免时间戳异常的流导致的内存暴增问题
|
||||
//而且sendmsg接口一般最多只能发送1024个数据包
|
||||
// 缓存数超过1024个,这个逻辑用于避免时间戳异常的流导致的内存暴增问题 [AUTO-TRANSLATED:f27e11f8]
|
||||
// The number of caches exceeds 1024, this logic is used to avoid memory explosion caused by streams with abnormal timestamps.
|
||||
// 而且sendmsg接口一般最多只能发送1024个数据包 [AUTO-TRANSLATED:872436e2]
|
||||
// Moreover, the sendmsg interface generally can only send a maximum of 1024 data packets.
|
||||
return cache_size >= 1024;
|
||||
}
|
||||
|
||||
bool FlushPolicy::isFlushAble(bool is_video, bool is_key, uint64_t new_stamp, size_t cache_size) {
|
||||
bool flush_flag = false;
|
||||
if (is_key && is_video) {
|
||||
//遇到关键帧flush掉前面的数据,确保关键帧为该组数据的第一帧,确保GOP缓存有效
|
||||
// 遇到关键帧flush掉前面的数据,确保关键帧为该组数据的第一帧,确保GOP缓存有效 [AUTO-TRANSLATED:e2ebbf9b]
|
||||
// Encounter a key frame, flush the previous data, ensure that the key frame is the first frame of this group of data, and ensure the GOP cache is valid.
|
||||
flush_flag = true;
|
||||
} else {
|
||||
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
|
||||
if (mergeWriteMS <= 0) {
|
||||
//关闭了合并写或者合并写阈值小于等于0
|
||||
// 关闭了合并写或者合并写阈值小于等于0 [AUTO-TRANSLATED:2397b647]
|
||||
// Merge writing is closed or the merge writing threshold is less than or equal to 0.
|
||||
flush_flag = isFlushAble_default(is_video, _last_stamp[is_video], new_stamp, cache_size);
|
||||
} else {
|
||||
flush_flag = isFlushAble_merge(is_video, _last_stamp[is_video], new_stamp, cache_size, mergeWriteMS);
|
||||
|
@ -56,42 +56,60 @@ public:
|
||||
|
||||
virtual ~MediaSourceEvent() = default;
|
||||
|
||||
// 获取媒体源类型
|
||||
// 获取媒体源类型 [AUTO-TRANSLATED:34290a69]
|
||||
// Get media source type
|
||||
virtual MediaOriginType getOriginType(MediaSource &sender) const { return MediaOriginType::unknown; }
|
||||
// 获取媒体源url或者文件路径
|
||||
// 获取媒体源url或者文件路径 [AUTO-TRANSLATED:fa34d795]
|
||||
// Get media source url or file path
|
||||
virtual std::string getOriginUrl(MediaSource &sender) const;
|
||||
// 获取媒体源客户端相关信息
|
||||
// 获取媒体源客户端相关信息 [AUTO-TRANSLATED:037ef910]
|
||||
// Get media source client related information
|
||||
virtual std::shared_ptr<toolkit::SockInfo> getOriginSock(MediaSource &sender) const { return nullptr; }
|
||||
|
||||
// 通知拖动进度条
|
||||
// 通知拖动进度条 [AUTO-TRANSLATED:561b17f7]
|
||||
// Notify drag progress bar
|
||||
virtual bool seekTo(MediaSource &sender, uint32_t stamp) { return false; }
|
||||
// 通知暂停或恢复
|
||||
// 通知暂停或恢复 [AUTO-TRANSLATED:ee3c219f]
|
||||
// Notify pause or resume
|
||||
virtual bool pause(MediaSource &sender, bool pause) { return false; }
|
||||
// 通知倍数
|
||||
// 通知倍数 [AUTO-TRANSLATED:8f1dab15]
|
||||
// Notify multiple times
|
||||
virtual bool speed(MediaSource &sender, float speed) { return false; }
|
||||
// 通知其停止产生流
|
||||
// 通知其停止产生流 [AUTO-TRANSLATED:62c9022c]
|
||||
// Notify it to stop generating streams
|
||||
virtual bool close(MediaSource &sender) { return false; }
|
||||
// 获取观看总人数,此函数一般强制重载
|
||||
// 获取观看总人数,此函数一般强制重载 [AUTO-TRANSLATED:1da20a10]
|
||||
// Get the total number of viewers, this function is generally forced to overload
|
||||
virtual int totalReaderCount(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::totalReaderCount not implemented"); }
|
||||
// 通知观看人数变化
|
||||
// 通知观看人数变化 [AUTO-TRANSLATED:bad89528]
|
||||
// Notify the change in the number of viewers
|
||||
virtual void onReaderChanged(MediaSource &sender, int size);
|
||||
//流注册或注销事件
|
||||
// 流注册或注销事件 [AUTO-TRANSLATED:2cac8178]
|
||||
// Stream registration or deregistration event
|
||||
virtual void onRegist(MediaSource &sender, bool regist) {}
|
||||
// 获取丢包率
|
||||
// 获取丢包率 [AUTO-TRANSLATED:ec61b378]
|
||||
// Get packet loss rate
|
||||
virtual float getLossRate(MediaSource &sender, TrackType type) { return -1; }
|
||||
// 获取所在线程, 此函数一般强制重载
|
||||
// 获取所在线程, 此函数一般强制重载 [AUTO-TRANSLATED:71c99afb]
|
||||
// Get the current thread, this function is generally forced to overload
|
||||
virtual toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) { throw NotImplemented(toolkit::demangle(typeid(*this).name()) + "::getOwnerPoller not implemented"); }
|
||||
|
||||
////////////////////////仅供MultiMediaSourceMuxer对象继承////////////////////////
|
||||
// 开启或关闭录制
|
||||
// //////////////////////仅供MultiMediaSourceMuxer对象继承//////////////////////// [AUTO-TRANSLATED:6e810d1f]
|
||||
// //////////////////////Only for MultiMediaSourceMuxer object inheritance////////////////////////
|
||||
// 开启或关闭录制 [AUTO-TRANSLATED:3817e390]
|
||||
// Start or stop recording
|
||||
virtual bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) { return false; };
|
||||
// 获取录制状态
|
||||
// 获取录制状态 [AUTO-TRANSLATED:a0499880]
|
||||
// Get recording status
|
||||
virtual bool isRecording(MediaSource &sender, Recorder::type type) { return false; }
|
||||
// 获取所有track相关信息
|
||||
// 获取所有track相关信息 [AUTO-TRANSLATED:2141be42]
|
||||
// Get all track related information
|
||||
virtual std::vector<Track::Ptr> getMediaTracks(MediaSource &sender, bool trackReady = true) const { return std::vector<Track::Ptr>(); };
|
||||
// 获取MultiMediaSourceMuxer对象
|
||||
// 获取MultiMediaSourceMuxer对象 [AUTO-TRANSLATED:2de96d44]
|
||||
// Get MultiMediaSourceMuxer object
|
||||
virtual std::shared_ptr<MultiMediaSourceMuxer> getMuxer(MediaSource &sender) const { return nullptr; }
|
||||
// 获取RtpProcess对象
|
||||
// 获取RtpProcess对象 [AUTO-TRANSLATED:c6b7da43]
|
||||
// Get RtpProcess object
|
||||
virtual std::shared_ptr<RtpProcess> getRtpProcess(MediaSource &sender) const { return nullptr; }
|
||||
|
||||
class SendRtpArgs {
|
||||
@ -109,45 +127,60 @@ public:
|
||||
kUdpPassive = 3 // udp被动方式,等待对方发送nat打洞包,然后回复rtp至打洞包源地址
|
||||
};
|
||||
|
||||
// rtp类型
|
||||
// rtp类型 [AUTO-TRANSLATED:acca40ab]
|
||||
// Rtp type
|
||||
DataType data_type = kRtpPS;
|
||||
// 连接类型
|
||||
// 连接类型 [AUTO-TRANSLATED:8ad5c881]
|
||||
// Connection type
|
||||
ConType con_type = kUdpActive;
|
||||
|
||||
// 发送es流时指定是否只发送纯音频流
|
||||
// 发送es流时指定是否只发送纯音频流 [AUTO-TRANSLATED:470c761e]
|
||||
// Specify whether to send only pure audio stream when sending es stream
|
||||
bool only_audio = false;
|
||||
// rtp payload type
|
||||
uint8_t pt = 96;
|
||||
// 是否支持同ssrc多服务器发送
|
||||
// 是否支持同ssrc多服务器发送 [AUTO-TRANSLATED:9d817af2]
|
||||
// Whether to support multiple servers sending with the same ssrc
|
||||
bool ssrc_multi_send = false;
|
||||
// 指定rtp ssrc
|
||||
// 指定rtp ssrc [AUTO-TRANSLATED:7366c6f9]
|
||||
// Specify rtp ssrc
|
||||
std::string ssrc;
|
||||
// 指定本地发送端口
|
||||
// 指定本地发送端口 [AUTO-TRANSLATED:f5d92f40]
|
||||
// Specify local sending port
|
||||
uint16_t src_port = 0;
|
||||
// 发送目标端口
|
||||
// 发送目标端口 [AUTO-TRANSLATED:096b5574]
|
||||
// Send target port
|
||||
uint16_t dst_port;
|
||||
// 发送目标主机地址,可以是ip或域名
|
||||
// 发送目标主机地址,可以是ip或域名 [AUTO-TRANSLATED:2c872f2e]
|
||||
// Send target host address, can be ip or domain name
|
||||
std::string dst_url;
|
||||
|
||||
// udp发送时,是否开启rr rtcp接收超时判断
|
||||
// udp发送时,是否开启rr rtcp接收超时判断 [AUTO-TRANSLATED:784982bd]
|
||||
// When sending udp, whether to enable rr rtcp receive timeout judgment
|
||||
bool udp_rtcp_timeout = false;
|
||||
// passive被动、tcp主动模式超时时间
|
||||
// passive被动、tcp主动模式超时时间 [AUTO-TRANSLATED:8886d475]
|
||||
// Passive passive, tcp active mode timeout time
|
||||
uint32_t close_delay_ms = 0;
|
||||
// udp 发送时,rr rtcp包接收超时时间,单位毫秒
|
||||
// udp 发送时,rr rtcp包接收超时时间,单位毫秒 [AUTO-TRANSLATED:9f0d91d9]
|
||||
// When sending udp, rr rtcp packet receive timeout time, in milliseconds
|
||||
uint32_t rtcp_timeout_ms = 30 * 1000;
|
||||
// udp 发送时,发送sr rtcp包间隔,单位毫秒
|
||||
// udp 发送时,发送sr rtcp包间隔,单位毫秒 [AUTO-TRANSLATED:c87bfed4]
|
||||
// When sending udp, send sr rtcp packet interval, in milliseconds
|
||||
uint32_t rtcp_send_interval_ms = 5 * 1000;
|
||||
|
||||
// 发送rtp同时接收,一般用于双向语言对讲, 如果不为空,说明开启接收
|
||||
// 发送rtp同时接收,一般用于双向语言对讲, 如果不为空,说明开启接收 [AUTO-TRANSLATED:f4c18084]
|
||||
// Send rtp while receiving, generally used for two-way language intercom, if not empty, it means receiving is enabled
|
||||
std::string recv_stream_id;
|
||||
|
||||
std::string recv_stream_app;
|
||||
std::string recv_stream_vhost;
|
||||
};
|
||||
|
||||
// 开始发送ps-rtp
|
||||
// 开始发送ps-rtp [AUTO-TRANSLATED:a51796fa]
|
||||
// Start sending ps-rtp
|
||||
virtual void startSendRtp(MediaSource &sender, const SendRtpArgs &args, const std::function<void(uint16_t, const toolkit::SockException &)> cb) { cb(0, toolkit::SockException(toolkit::Err_other, "not implemented"));};
|
||||
// 停止发送ps-rtp
|
||||
// 停止发送ps-rtp [AUTO-TRANSLATED:952d2b35]
|
||||
// Stop sending ps-rtp
|
||||
virtual bool stopSendRtp(MediaSource &sender, const std::string &ssrc) {return false; }
|
||||
|
||||
private:
|
||||
@ -180,65 +213,92 @@ public:
|
||||
kModifyStampSystem = 1, // 采用zlmediakit接收数据时的系统时间戳(有平滑处理)
|
||||
kModifyStampRelative = 2 // 采用源视频流时间戳相对时间戳(增长量),有做时间戳跳跃和回退矫正
|
||||
};
|
||||
// 时间戳类型
|
||||
// 时间戳类型 [AUTO-TRANSLATED:7d2779e1]
|
||||
// Timestamp type
|
||||
int modify_stamp;
|
||||
|
||||
//转协议是否开启音频
|
||||
// 转协议是否开启音频 [AUTO-TRANSLATED:220dddfa]
|
||||
// Whether to enable audio for protocol conversion
|
||||
bool enable_audio;
|
||||
//添加静音音频,在关闭音频时,此开关无效
|
||||
// 添加静音音频,在关闭音频时,此开关无效 [AUTO-TRANSLATED:47c0ec8e]
|
||||
// Add mute audio, this switch is invalid when audio is closed
|
||||
bool add_mute_audio;
|
||||
// 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close)
|
||||
// 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调,
|
||||
// 而是将直接关闭流
|
||||
// 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close) [AUTO-TRANSLATED:dba7ab70]
|
||||
// Whether to close directly when no one is watching (instead of returning close through the on_none_reader hook)
|
||||
// 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调, [AUTO-TRANSLATED:a5ead314]
|
||||
// When this configuration is set to 1, if no one is watching this stream, it will not trigger the on_none_reader hook callback,
|
||||
// 而是将直接关闭流 [AUTO-TRANSLATED:06887d49]
|
||||
// but will directly close the stream
|
||||
bool auto_close;
|
||||
|
||||
//断连续推延时,单位毫秒,默认采用配置文件
|
||||
// 断连续推延时,单位毫秒,默认采用配置文件 [AUTO-TRANSLATED:7a15b12f]
|
||||
// Delay in milliseconds for continuous pushing, default is using the configuration file
|
||||
uint32_t continue_push_ms;
|
||||
|
||||
// 平滑发送定时器间隔,单位毫秒,置0则关闭;开启后影响cpu性能同时增加内存
|
||||
// 该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题
|
||||
// 平滑发送定时器间隔,单位毫秒,置0则关闭;开启后影响cpu性能同时增加内存 [AUTO-TRANSLATED:ad4e306a]
|
||||
// Smooth sending timer interval, in milliseconds, set to 0 to close; enabling it will affect cpu performance and increase memory at the same time
|
||||
// 该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题 [AUTO-TRANSLATED:0f2b1657]
|
||||
// This configuration can solve some problems where the stream is not sent smoothly, resulting in zlmediakit forwarding not being smooth
|
||||
uint32_t paced_sender_ms;
|
||||
|
||||
//是否开启转换为hls(mpegts)
|
||||
// 是否开启转换为hls(mpegts) [AUTO-TRANSLATED:bfc1167a]
|
||||
// Whether to enable conversion to hls(mpegts)
|
||||
bool enable_hls;
|
||||
//是否开启转换为hls(fmp4)
|
||||
// 是否开启转换为hls(fmp4) [AUTO-TRANSLATED:20548673]
|
||||
// Whether to enable conversion to hls(fmp4)
|
||||
bool enable_hls_fmp4;
|
||||
//是否开启MP4录制
|
||||
// 是否开启MP4录制 [AUTO-TRANSLATED:0157b014]
|
||||
// Whether to enable MP4 recording
|
||||
bool enable_mp4;
|
||||
//是否开启转换为rtsp/webrtc
|
||||
// 是否开启转换为rtsp/webrtc [AUTO-TRANSLATED:0711cb18]
|
||||
// Whether to enable conversion to rtsp/webrtc
|
||||
bool enable_rtsp;
|
||||
//是否开启转换为rtmp/flv
|
||||
// 是否开启转换为rtmp/flv [AUTO-TRANSLATED:d4774119]
|
||||
// Whether to enable conversion to rtmp/flv
|
||||
bool enable_rtmp;
|
||||
//是否开启转换为http-ts/ws-ts
|
||||
// 是否开启转换为http-ts/ws-ts [AUTO-TRANSLATED:51acc798]
|
||||
// Whether to enable conversion to http-ts/ws-ts
|
||||
bool enable_ts;
|
||||
//是否开启转换为http-fmp4/ws-fmp4
|
||||
// 是否开启转换为http-fmp4/ws-fmp4 [AUTO-TRANSLATED:8c96e1e4]
|
||||
// Whether to enable conversion to http-fmp4/ws-fmp4
|
||||
bool enable_fmp4;
|
||||
|
||||
// hls协议是否按需生成,如果hls.segNum配置为0(意味着hls录制),那么hls将一直生成(不管此开关)
|
||||
// hls协议是否按需生成,如果hls.segNum配置为0(意味着hls录制),那么hls将一直生成(不管此开关) [AUTO-TRANSLATED:4653b411]
|
||||
// Whether to generate hls protocol on demand, if hls.segNum is configured to 0 (meaning hls recording), then hls will always be generated (regardless of this switch)
|
||||
bool hls_demand;
|
||||
// rtsp[s]协议是否按需生成
|
||||
// rtsp[s]协议是否按需生成 [AUTO-TRANSLATED:1c3237b0]
|
||||
// Whether to generate rtsp[s] protocol on demand
|
||||
bool rtsp_demand;
|
||||
// rtmp[s]、http[s]-flv、ws[s]-flv协议是否按需生成
|
||||
// rtmp[s]、http[s]-flv、ws[s]-flv协议是否按需生成 [AUTO-TRANSLATED:09ed2c30]
|
||||
// Whether to generate rtmp[s]、http[s]-flv、ws[s]-flv protocol on demand
|
||||
bool rtmp_demand;
|
||||
// http[s]-ts协议是否按需生成
|
||||
// http[s]-ts协议是否按需生成 [AUTO-TRANSLATED:a0129db3]
|
||||
// Whether to generate http[s]-ts protocol on demand
|
||||
bool ts_demand;
|
||||
// http[s]-fmp4、ws[s]-fmp4协议是否按需生成
|
||||
// http[s]-fmp4、ws[s]-fmp4协议是否按需生成 [AUTO-TRANSLATED:828d25c7]
|
||||
// Whether to generate http[s]-fmp4、ws[s]-fmp4 protocol on demand
|
||||
bool fmp4_demand;
|
||||
|
||||
//是否将mp4录制当做观看者
|
||||
// 是否将mp4录制当做观看者 [AUTO-TRANSLATED:ba351230]
|
||||
// Whether to treat mp4 recording as a viewer
|
||||
bool mp4_as_player;
|
||||
//mp4切片大小,单位秒
|
||||
// mp4切片大小,单位秒 [AUTO-TRANSLATED:c3fb8ec1]
|
||||
// MP4 slice size, in seconds
|
||||
size_t mp4_max_second;
|
||||
//mp4录制保存路径
|
||||
// mp4录制保存路径 [AUTO-TRANSLATED:6d860f27]
|
||||
// MP4 recording save path
|
||||
std::string mp4_save_path;
|
||||
|
||||
//hls录制保存路径
|
||||
// hls录制保存路径 [AUTO-TRANSLATED:cfa90719]
|
||||
// HLS recording save path
|
||||
std::string hls_save_path;
|
||||
|
||||
// 支持通过on_publish返回值替换stream_id
|
||||
// 支持通过on_publish返回值替换stream_id [AUTO-TRANSLATED:2c4e4997]
|
||||
// Support replacing stream_id through the return value of on_publish
|
||||
std::string stream_replace;
|
||||
|
||||
// 最大track数
|
||||
// 最大track数 [AUTO-TRANSLATED:2565fd37]
|
||||
// Maximum number of tracks
|
||||
size_t max_track = 2;
|
||||
|
||||
template <typename MAP>
|
||||
@ -280,7 +340,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//该对象用于拦截感兴趣的MediaSourceEvent事件
|
||||
// 该对象用于拦截感兴趣的MediaSourceEvent事件 [AUTO-TRANSLATED:fd6d0559]
|
||||
// This object is used to intercept interesting MediaSourceEvent events
|
||||
class MediaSourceEventInterceptor : public MediaSourceEvent {
|
||||
public:
|
||||
void setDelegate(const std::weak_ptr<MediaSourceEvent> &listener);
|
||||
@ -313,6 +374,9 @@ private:
|
||||
|
||||
/**
|
||||
* 解析url获取媒体相关信息
|
||||
* Parse the url to get media information
|
||||
|
||||
* [AUTO-TRANSLATED:3b3cfde7]
|
||||
*/
|
||||
class MediaInfo: public MediaTuple {
|
||||
public:
|
||||
@ -332,6 +396,9 @@ bool equalMediaTuple(const MediaTuple& a, const MediaTuple& b);
|
||||
|
||||
/**
|
||||
* 媒体源,任何rtsp/rtmp的直播流都源自该对象
|
||||
* Media source, any rtsp/rtmp live stream originates from this object
|
||||
|
||||
* [AUTO-TRANSLATED:658077ad]
|
||||
*/
|
||||
class MediaSource: public TrackSource, public std::enable_shared_from_this<MediaSource> {
|
||||
public:
|
||||
@ -341,9 +408,11 @@ public:
|
||||
MediaSource(const std::string &schema, const MediaTuple& tuple);
|
||||
virtual ~MediaSource();
|
||||
|
||||
////////////////获取MediaSource相关信息////////////////
|
||||
// //////////////获取MediaSource相关信息//////////////// [AUTO-TRANSLATED:4a520f1f]
|
||||
// //////////////Get MediaSource information////////////////
|
||||
|
||||
// 获取协议类型
|
||||
// 获取协议类型 [AUTO-TRANSLATED:d6b50c14]
|
||||
// Get protocol type
|
||||
const std::string& getSchema() const {
|
||||
return _schema;
|
||||
}
|
||||
@ -354,36 +423,49 @@ public:
|
||||
|
||||
std::string getUrl() const { return _schema + "://" + _tuple.shortUrl(); }
|
||||
|
||||
//获取对象所有权
|
||||
// 获取对象所有权 [AUTO-TRANSLATED:84fb43cd]
|
||||
// Get object ownership
|
||||
std::shared_ptr<void> getOwnership();
|
||||
|
||||
// 获取所有Track
|
||||
// 获取所有Track [AUTO-TRANSLATED:59f1c570]
|
||||
// Get all Tracks
|
||||
std::vector<Track::Ptr> getTracks(bool ready = true) const override;
|
||||
|
||||
// 获取流当前时间戳
|
||||
// 获取流当前时间戳 [AUTO-TRANSLATED:f65f560a]
|
||||
// Get the current timestamp of the stream
|
||||
virtual uint32_t getTimeStamp(TrackType type) { return 0; };
|
||||
// 设置时间戳
|
||||
// 设置时间戳 [AUTO-TRANSLATED:2bfce32f]
|
||||
// Set timestamp
|
||||
virtual void setTimeStamp(uint32_t stamp) {};
|
||||
|
||||
// 获取数据速率,单位bytes/s
|
||||
// 获取数据速率,单位bytes/s [AUTO-TRANSLATED:c70465c1]
|
||||
// Get data rate, unit bytes/s
|
||||
int getBytesSpeed(TrackType type = TrackInvalid);
|
||||
// 获取流创建GMT unix时间戳,单位秒
|
||||
// 获取流创建GMT unix时间戳,单位秒 [AUTO-TRANSLATED:0bbe145e]
|
||||
// Get the stream creation GMT unix timestamp, unit seconds
|
||||
uint64_t getCreateStamp() const { return _create_stamp; }
|
||||
// 获取流上线时间,单位秒
|
||||
// 获取流上线时间,单位秒 [AUTO-TRANSLATED:a087d56a]
|
||||
// Get the stream online time, unit seconds
|
||||
uint64_t getAliveSecond() const;
|
||||
|
||||
////////////////MediaSourceEvent相关接口实现////////////////
|
||||
// //////////////MediaSourceEvent相关接口实现//////////////// [AUTO-TRANSLATED:aa63d949]
|
||||
// //////////////MediaSourceEvent related interface implementation////////////////
|
||||
|
||||
// 设置监听者
|
||||
// 设置监听者 [AUTO-TRANSLATED:b9b90b57]
|
||||
// Set listener
|
||||
virtual void setListener(const std::weak_ptr<MediaSourceEvent> &listener);
|
||||
// 获取监听者
|
||||
// 获取监听者 [AUTO-TRANSLATED:5c9cbb82]
|
||||
// Get listener
|
||||
std::weak_ptr<MediaSourceEvent> getListener() const;
|
||||
|
||||
// 本协议获取观看者个数,可能返回本协议的观看人数,也可能返回总人数
|
||||
// 本协议获取观看者个数,可能返回本协议的观看人数,也可能返回总人数 [AUTO-TRANSLATED:0874fa7c]
|
||||
// This protocol gets the number of viewers, it may return the number of viewers of this protocol, or it may return the total number of viewers
|
||||
virtual int readerCount() = 0;
|
||||
// 观看者个数,包括(hls/rtsp/rtmp)
|
||||
// 观看者个数,包括(hls/rtsp/rtmp) [AUTO-TRANSLATED:6604020f]
|
||||
// Number of viewers, including (hls/rtsp/rtmp)
|
||||
virtual int totalReaderCount();
|
||||
// 获取播放器列表
|
||||
// 获取播放器列表 [AUTO-TRANSLATED:e7691d2b]
|
||||
// Get the player list
|
||||
virtual void getPlayerList(const std::function<void(const std::list<toolkit::Any> &info_list)> &cb,
|
||||
const std::function<toolkit::Any(toolkit::Any &&info)> &on_change) {
|
||||
assert(cb);
|
||||
@ -392,66 +474,91 @@ public:
|
||||
|
||||
virtual bool broadcastMessage(const toolkit::Any &data) { return false; }
|
||||
|
||||
// 获取媒体源类型
|
||||
// 获取媒体源类型 [AUTO-TRANSLATED:34290a69]
|
||||
// Get the media source type
|
||||
MediaOriginType getOriginType() const;
|
||||
// 获取媒体源url或者文件路径
|
||||
// 获取媒体源url或者文件路径 [AUTO-TRANSLATED:fa34d795]
|
||||
// Get the media source url or file path
|
||||
std::string getOriginUrl() const;
|
||||
// 获取媒体源客户端相关信息
|
||||
// 获取媒体源客户端相关信息 [AUTO-TRANSLATED:037ef910]
|
||||
// Get the media source client information
|
||||
std::shared_ptr<toolkit::SockInfo> getOriginSock() const;
|
||||
|
||||
// 拖动进度条
|
||||
// 拖动进度条 [AUTO-TRANSLATED:65ee8a83]
|
||||
// Drag the progress bar
|
||||
bool seekTo(uint32_t stamp);
|
||||
// 暂停
|
||||
// 暂停 [AUTO-TRANSLATED:ffd21ae7]
|
||||
// Pause
|
||||
bool pause(bool pause);
|
||||
// 倍数播放
|
||||
// 倍数播放 [AUTO-TRANSLATED:a5e3c1c9]
|
||||
// Playback speed
|
||||
bool speed(float speed);
|
||||
// 关闭该流
|
||||
// 关闭该流 [AUTO-TRANSLATED:b3867b98]
|
||||
// Close the stream
|
||||
bool close(bool force);
|
||||
// 该流观看人数变化
|
||||
// 该流观看人数变化 [AUTO-TRANSLATED:8e583993]
|
||||
// The number of viewers of this stream changes
|
||||
void onReaderChanged(int size);
|
||||
// 开启或关闭录制
|
||||
// 开启或关闭录制 [AUTO-TRANSLATED:3817e390]
|
||||
// Turn recording on or off
|
||||
bool setupRecord(Recorder::type type, bool start, const std::string &custom_path, size_t max_second);
|
||||
// 获取录制状态
|
||||
// 获取录制状态 [AUTO-TRANSLATED:a0499880]
|
||||
// Get recording status
|
||||
bool isRecording(Recorder::type type);
|
||||
// 开始发送ps-rtp
|
||||
// 开始发送ps-rtp [AUTO-TRANSLATED:a51796fa]
|
||||
// Start sending ps-rtp
|
||||
void startSendRtp(const MediaSourceEvent::SendRtpArgs &args, const std::function<void(uint16_t, const toolkit::SockException &)> cb);
|
||||
// 停止发送ps-rtp
|
||||
// 停止发送ps-rtp [AUTO-TRANSLATED:952d2b35]
|
||||
// Stop sending ps-rtp
|
||||
bool stopSendRtp(const std::string &ssrc);
|
||||
// 获取丢包率
|
||||
// 获取丢包率 [AUTO-TRANSLATED:ec61b378]
|
||||
// Get packet loss rate
|
||||
float getLossRate(mediakit::TrackType type);
|
||||
// 获取所在线程
|
||||
// 获取所在线程 [AUTO-TRANSLATED:75662eb8]
|
||||
// Get the thread where it is running
|
||||
toolkit::EventPoller::Ptr getOwnerPoller();
|
||||
// 获取MultiMediaSourceMuxer对象
|
||||
// 获取MultiMediaSourceMuxer对象 [AUTO-TRANSLATED:2de96d44]
|
||||
// Get the MultiMediaSourceMuxer object
|
||||
std::shared_ptr<MultiMediaSourceMuxer> getMuxer() const;
|
||||
// 获取RtpProcess对象
|
||||
// 获取RtpProcess对象 [AUTO-TRANSLATED:c6b7da43]
|
||||
// Get the RtpProcess object
|
||||
std::shared_ptr<RtpProcess> getRtpProcess() const;
|
||||
|
||||
////////////////static方法,查找或生成MediaSource////////////////
|
||||
// //////////////static方法,查找或生成MediaSource//////////////// [AUTO-TRANSLATED:c3950036]
|
||||
// //////////////static methods, find or generate MediaSource////////////////
|
||||
|
||||
// 同步查找流
|
||||
// 同步查找流 [AUTO-TRANSLATED:97048f1e]
|
||||
// Synchronously find the stream
|
||||
static Ptr find(const std::string &schema, const std::string &vhost, const std::string &app, const std::string &id, bool from_mp4 = false);
|
||||
static Ptr find(const MediaInfo &info, bool from_mp4 = false) {
|
||||
return find(info.schema, info.vhost, info.app, info.stream, from_mp4);
|
||||
}
|
||||
|
||||
// 忽略schema,同步查找流,可能返回rtmp/rtsp/hls类型
|
||||
// 忽略schema,同步查找流,可能返回rtmp/rtsp/hls类型 [AUTO-TRANSLATED:8c061cac]
|
||||
// Ignore schema, synchronously find the stream, may return rtmp/rtsp/hls type
|
||||
static Ptr find(const std::string &vhost, const std::string &app, const std::string &stream_id, bool from_mp4 = false);
|
||||
|
||||
// 异步查找流
|
||||
// 异步查找流 [AUTO-TRANSLATED:4decf738]
|
||||
// Asynchronously find the stream
|
||||
static void findAsync(const MediaInfo &info, const std::shared_ptr<toolkit::Session> &session, const std::function<void(const Ptr &src)> &cb);
|
||||
// 遍历所有流
|
||||
// 遍历所有流 [AUTO-TRANSLATED:a39b2399]
|
||||
// Traverse all streams
|
||||
static void for_each_media(const std::function<void(const Ptr &src)> &cb, const std::string &schema = "", const std::string &vhost = "", const std::string &app = "", const std::string &stream = "");
|
||||
// 从mp4文件生成MediaSource
|
||||
// 从mp4文件生成MediaSource [AUTO-TRANSLATED:7df9762e]
|
||||
// Generate MediaSource from mp4 file
|
||||
static MediaSource::Ptr createFromMP4(const std::string &schema, const std::string &vhost, const std::string &app, const std::string &stream, const std::string &file_path = "", bool check_app = true);
|
||||
|
||||
protected:
|
||||
//媒体注册
|
||||
// 媒体注册 [AUTO-TRANSLATED:dbf5c730]
|
||||
// Media registration
|
||||
void regist();
|
||||
|
||||
private:
|
||||
// 媒体注销
|
||||
// 媒体注销 [AUTO-TRANSLATED:06a0630a]
|
||||
// Media unregistration
|
||||
bool unregist();
|
||||
// 触发媒体事件
|
||||
// 触发媒体事件 [AUTO-TRANSLATED:0c2f9ae6]
|
||||
// Trigger media events
|
||||
void emitEvent(bool regist);
|
||||
|
||||
protected:
|
||||
@ -464,7 +571,8 @@ private:
|
||||
toolkit::Ticker _ticker;
|
||||
std::string _schema;
|
||||
std::weak_ptr<MediaSourceEvent> _listener;
|
||||
// 对象个数统计
|
||||
// 对象个数统计 [AUTO-TRANSLATED:f4a012d0]
|
||||
// Object count statistics
|
||||
toolkit::ObjectStatistic<MediaSource> _statistic;
|
||||
};
|
||||
|
||||
|
@ -35,7 +35,8 @@ public:
|
||||
class FramePacedSender : public FrameWriterInterface, public std::enable_shared_from_this<FramePacedSender> {
|
||||
public:
|
||||
using OnFrame = std::function<void(const Frame::Ptr &frame)>;
|
||||
// 最小缓存100ms数据
|
||||
// 最小缓存100ms数据 [AUTO-TRANSLATED:7b2fcb0d]
|
||||
// Minimum cache 100ms data
|
||||
static constexpr auto kMinCacheMS = 100;
|
||||
|
||||
FramePacedSender(uint32_t paced_sender_ms, OnFrame cb) {
|
||||
@ -73,21 +74,25 @@ private:
|
||||
while (!_cache.empty()) {
|
||||
auto &front = _cache.front();
|
||||
if (getCurrentStamp() < front.first) {
|
||||
// 还没到消费时间
|
||||
// 还没到消费时间 [AUTO-TRANSLATED:09fb4c3d]
|
||||
// Not yet time to consume
|
||||
break;
|
||||
}
|
||||
// 时间到了,该消费frame了
|
||||
// 时间到了,该消费frame了 [AUTO-TRANSLATED:2f007931]
|
||||
// Time is up, it's time to consume the frame
|
||||
_cb(front.second);
|
||||
_cache.pop_front();
|
||||
}
|
||||
|
||||
if (_cache.empty() && dst) {
|
||||
// 消费太快,需要增加缓存大小
|
||||
// 消费太快,需要增加缓存大小 [AUTO-TRANSLATED:c05bfbcd]
|
||||
// Consumption is too fast, need to increase cache size
|
||||
setCurrentStamp(dst);
|
||||
_cache_ms += kMinCacheMS;
|
||||
}
|
||||
|
||||
// 消费太慢,需要强制flush数据
|
||||
// 消费太慢,需要强制flush数据 [AUTO-TRANSLATED:5613625e]
|
||||
// Consumption is too slow, need to force flush data
|
||||
if (_cache.size() > 25 * 5) {
|
||||
WarnL << "Flush frame paced sender cache: " << _cache.size();
|
||||
while (!_cache.empty()) {
|
||||
@ -181,7 +186,8 @@ void MultiMediaSourceMuxer::forEachRtpSender(const std::function<void(const std:
|
||||
|
||||
MultiMediaSourceMuxer::MultiMediaSourceMuxer(const MediaTuple& tuple, float dur_sec, const ProtocolOption &option): _tuple(tuple) {
|
||||
if (!option.stream_replace.empty()) {
|
||||
// 支持在on_publish hook中替换stream_id
|
||||
// 支持在on_publish hook中替换stream_id [AUTO-TRANSLATED:375eb2ff]
|
||||
// Support replacing stream_id in on_publish hook
|
||||
_tuple.stream = option.stream_replace;
|
||||
}
|
||||
_poller = EventPollerPool::Instance().getPoller();
|
||||
@ -212,7 +218,8 @@ MultiMediaSourceMuxer::MultiMediaSourceMuxer(const MediaTuple& tuple, float dur_
|
||||
_fmp4 = dynamic_pointer_cast<FMP4MediaSourceMuxer>(Recorder::createRecorder(Recorder::type_fmp4, _tuple, option));
|
||||
}
|
||||
|
||||
//音频相关设置
|
||||
// 音频相关设置 [AUTO-TRANSLATED:6ee58d57]
|
||||
// Audio related settings
|
||||
enableAudio(option.enable_audio);
|
||||
enableMuteAudio(option.add_mute_audio);
|
||||
}
|
||||
@ -221,7 +228,8 @@ void MultiMediaSourceMuxer::setMediaListener(const std::weak_ptr<MediaSourceEven
|
||||
setDelegate(listener);
|
||||
|
||||
auto self = shared_from_this();
|
||||
//拦截事件
|
||||
// 拦截事件 [AUTO-TRANSLATED:100ca068]
|
||||
// Intercept events
|
||||
if (_rtmp) {
|
||||
_rtmp->setListener(self);
|
||||
}
|
||||
@ -274,61 +282,72 @@ int MultiMediaSourceMuxer::totalReaderCount(MediaSource &sender) {
|
||||
try {
|
||||
return listener->totalReaderCount(sender);
|
||||
} catch (MediaSourceEvent::NotImplemented &) {
|
||||
//listener未重载totalReaderCount
|
||||
// listener未重载totalReaderCount [AUTO-TRANSLATED:f098007e]
|
||||
// Listener did not reload totalReaderCount
|
||||
return totalReaderCount();
|
||||
}
|
||||
}
|
||||
|
||||
//此函数可能跨线程调用
|
||||
// 此函数可能跨线程调用 [AUTO-TRANSLATED:e8c5f74d]
|
||||
// This function may be called across threads
|
||||
bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path, size_t max_second) {
|
||||
CHECK(getOwnerPoller(MediaSource::NullMediaSource())->isCurrentThread(), "Can only call setupRecord in it's owner poller");
|
||||
onceToken token(nullptr, [&]() {
|
||||
if (_option.mp4_as_player && type == Recorder::type_mp4) {
|
||||
//开启关闭mp4录制,触发观看人数变化相关事件
|
||||
// 开启关闭mp4录制,触发观看人数变化相关事件 [AUTO-TRANSLATED:b63a8deb]
|
||||
// Turn on/off mp4 recording, trigger events related to changes in the number of viewers
|
||||
onReaderChanged(sender, totalReaderCount());
|
||||
}
|
||||
});
|
||||
switch (type) {
|
||||
case Recorder::type_hls : {
|
||||
if (start && !_hls) {
|
||||
//开始录制
|
||||
// 开始录制 [AUTO-TRANSLATED:36d99250]
|
||||
// Start recording
|
||||
_option.hls_save_path = custom_path;
|
||||
auto hls = dynamic_pointer_cast<HlsRecorder>(makeRecorder(sender, getTracks(), type, _option));
|
||||
if (hls) {
|
||||
//设置HlsMediaSource的事件监听器
|
||||
// 设置HlsMediaSource的事件监听器 [AUTO-TRANSLATED:69990c92]
|
||||
// Set the event listener for HlsMediaSource
|
||||
hls->setListener(shared_from_this());
|
||||
}
|
||||
_hls = hls;
|
||||
} else if (!start && _hls) {
|
||||
//停止录制
|
||||
// 停止录制 [AUTO-TRANSLATED:3dee9292]
|
||||
// Stop recording
|
||||
_hls = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Recorder::type_mp4 : {
|
||||
if (start && !_mp4) {
|
||||
//开始录制
|
||||
// 开始录制 [AUTO-TRANSLATED:36d99250]
|
||||
// Start recording
|
||||
_option.mp4_save_path = custom_path;
|
||||
_option.mp4_max_second = max_second;
|
||||
_mp4 = makeRecorder(sender, getTracks(), type, _option);
|
||||
} else if (!start && _mp4) {
|
||||
//停止录制
|
||||
// 停止录制 [AUTO-TRANSLATED:3dee9292]
|
||||
// Stop recording
|
||||
_mp4 = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Recorder::type_hls_fmp4: {
|
||||
if (start && !_hls_fmp4) {
|
||||
//开始录制
|
||||
// 开始录制 [AUTO-TRANSLATED:36d99250]
|
||||
// Start recording
|
||||
_option.hls_save_path = custom_path;
|
||||
auto hls = dynamic_pointer_cast<HlsFMP4Recorder>(makeRecorder(sender, getTracks(), type, _option));
|
||||
if (hls) {
|
||||
//设置HlsMediaSource的事件监听器
|
||||
// 设置HlsMediaSource的事件监听器 [AUTO-TRANSLATED:69990c92]
|
||||
// Set the event listener for HlsMediaSource
|
||||
hls->setListener(shared_from_this());
|
||||
}
|
||||
_hls_fmp4 = hls;
|
||||
} else if (!start && _hls_fmp4) {
|
||||
//停止录制
|
||||
// 停止录制 [AUTO-TRANSLATED:3dee9292]
|
||||
// Stop recording
|
||||
_hls_fmp4 = nullptr;
|
||||
}
|
||||
return true;
|
||||
@ -361,7 +380,8 @@ bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type
|
||||
}
|
||||
}
|
||||
|
||||
//此函数可能跨线程调用
|
||||
// 此函数可能跨线程调用 [AUTO-TRANSLATED:e8c5f74d]
|
||||
// This function may be called across threads
|
||||
bool MultiMediaSourceMuxer::isRecording(MediaSource &sender, Recorder::type type) {
|
||||
switch (type) {
|
||||
case Recorder::type_hls: return !!_hls;
|
||||
@ -388,7 +408,8 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE
|
||||
|
||||
rtp_sender->setOnClose([weak_self, ssrc](const toolkit::SockException &ex) {
|
||||
if (auto strong_self = weak_self.lock()) {
|
||||
// 可能归属线程发生变更
|
||||
// 可能归属线程发生变更 [AUTO-TRANSLATED:2b379e30]
|
||||
// The owning thread may change
|
||||
strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() {
|
||||
WarnL << "stream:" << strong_self->shortUrl() << " stop send rtp:" << ssrc << ", reason:" << ex;
|
||||
strong_self->_rtp_sender.erase(ssrc);
|
||||
@ -414,7 +435,8 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE
|
||||
rtp_sender->inputFrame(frame);
|
||||
});
|
||||
|
||||
// 可能归属线程发生变更
|
||||
// 可能归属线程发生变更 [AUTO-TRANSLATED:2b379e30]
|
||||
// The owning thread may change
|
||||
strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() {
|
||||
if(!ssrc_multi_send) {
|
||||
strong_self->_rtp_sender.erase(ssrc);
|
||||
@ -430,12 +452,14 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE
|
||||
bool MultiMediaSourceMuxer::stopSendRtp(MediaSource &sender, const string &ssrc) {
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
if (ssrc.empty()) {
|
||||
//关闭全部
|
||||
// 关闭全部 [AUTO-TRANSLATED:ffaadfda]
|
||||
// Close all
|
||||
auto size = _rtp_sender.size();
|
||||
_rtp_sender.clear();
|
||||
return size;
|
||||
}
|
||||
//关闭特定的
|
||||
// 关闭特定的 [AUTO-TRANSLATED:2286322a]
|
||||
// Close specific
|
||||
return _rtp_sender.erase(ssrc);
|
||||
#else
|
||||
return false;
|
||||
@ -462,7 +486,8 @@ EventPoller::Ptr MultiMediaSourceMuxer::getOwnerPoller(MediaSource &sender) {
|
||||
}
|
||||
return ret;
|
||||
} catch (MediaSourceEvent::NotImplemented &) {
|
||||
// listener未重载getOwnerPoller
|
||||
// listener未重载getOwnerPoller [AUTO-TRANSLATED:0ebf2e53]
|
||||
// Listener did not reload getOwnerPoller
|
||||
return _poller;
|
||||
}
|
||||
}
|
||||
@ -474,7 +499,8 @@ std::shared_ptr<MultiMediaSourceMuxer> MultiMediaSourceMuxer::getMuxer(MediaSour
|
||||
bool MultiMediaSourceMuxer::onTrackReady(const Track::Ptr &track) {
|
||||
auto &stamp = _stamps[track->getIndex()];
|
||||
if (_dur_sec > 0.01) {
|
||||
// 点播
|
||||
// 点播 [AUTO-TRANSLATED:f0b0f74a]
|
||||
// On-demand
|
||||
stamp.setPlayBack();
|
||||
}
|
||||
|
||||
@ -570,7 +596,8 @@ void MultiMediaSourceMuxer::createGopCacheIfNeed() {
|
||||
auto src = std::make_shared<MediaSourceForMuxer>(weak_self.lock());
|
||||
_ring = std::make_shared<RingType>(1024, [weak_self, src](int size) {
|
||||
if (auto strong_self = weak_self.lock()) {
|
||||
// 切换到归属线程
|
||||
// 切换到归属线程 [AUTO-TRANSLATED:abcf859b]
|
||||
// Switch to the owning thread
|
||||
strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() {
|
||||
strong_self->onReaderChanged(*src, strong_self->totalReaderCount());
|
||||
});
|
||||
@ -607,7 +634,8 @@ void MultiMediaSourceMuxer::resetTracks() {
|
||||
bool MultiMediaSourceMuxer::onTrackFrame(const Frame::Ptr &frame_in) {
|
||||
auto frame = frame_in;
|
||||
if (_option.modify_stamp != ProtocolOption::kModifyStampOff) {
|
||||
// 时间戳不采用原始的绝对时间戳
|
||||
// 时间戳不采用原始的绝对时间戳 [AUTO-TRANSLATED:8beb3bf7]
|
||||
// Timestamp does not use the original absolute timestamp
|
||||
frame = std::make_shared<FrameStamp>(frame, _stamps[frame->getIndex()], _option.modify_stamp);
|
||||
}
|
||||
return _paced_sender ? _paced_sender->inputFrame(frame) : onTrackFrame_l(frame);
|
||||
@ -641,17 +669,20 @@ bool MultiMediaSourceMuxer::onTrackFrame_l(const Frame::Ptr &frame_in) {
|
||||
ret = _fmp4->inputFrame(frame) ? true : ret;
|
||||
}
|
||||
if (_ring) {
|
||||
// 此场景由于直接转发,可能存在切换线程引起的数据被缓存在管道,所以需要CacheAbleFrame
|
||||
// 此场景由于直接转发,可能存在切换线程引起的数据被缓存在管道,所以需要CacheAbleFrame [AUTO-TRANSLATED:528afbb7]
|
||||
// In this scenario, due to direct forwarding, there may be data cached in the pipeline due to thread switching, so CacheAbleFrame is needed
|
||||
frame = Frame::getCacheAbleFrame(frame);
|
||||
if (frame->getTrackType() == TrackVideo) {
|
||||
// 视频时,遇到第一帧配置帧或关键帧则标记为gop开始处
|
||||
// 视频时,遇到第一帧配置帧或关键帧则标记为gop开始处 [AUTO-TRANSLATED:66247aa8]
|
||||
// When it is a video, if the first frame configuration frame or key frame is encountered, it is marked as the beginning of the GOP
|
||||
auto video_key_pos = frame->keyFrame() || frame->configFrame();
|
||||
_ring->write(frame, video_key_pos && !_video_key_pos);
|
||||
if (!frame->dropAble()) {
|
||||
_video_key_pos = video_key_pos;
|
||||
}
|
||||
} else {
|
||||
// 没有视频时,设置is_key为true,目的是关闭gop缓存
|
||||
// 没有视频时,设置is_key为true,目的是关闭gop缓存 [AUTO-TRANSLATED:f3223755]
|
||||
// When there is no video, set is_key to true to disable gop caching
|
||||
_ring->write(frame, !haveVideo());
|
||||
}
|
||||
}
|
||||
@ -661,8 +692,10 @@ bool MultiMediaSourceMuxer::onTrackFrame_l(const Frame::Ptr &frame_in) {
|
||||
bool MultiMediaSourceMuxer::isEnabled(){
|
||||
GET_CONFIG(uint32_t, stream_none_reader_delay_ms, General::kStreamNoneReaderDelayMS);
|
||||
if (!_is_enable || _last_check.elapsedTime() > stream_none_reader_delay_ms) {
|
||||
//无人观看时,每次检查是否真的无人观看
|
||||
//有人观看时,则延迟一定时间检查一遍是否无人观看了(节省性能)
|
||||
// 无人观看时,每次检查是否真的无人观看 [AUTO-TRANSLATED:48bc59c6]
|
||||
// When no one is watching, check each time if there is really no one watching
|
||||
// 有人观看时,则延迟一定时间检查一遍是否无人观看了(节省性能) [AUTO-TRANSLATED:a7dfddc4]
|
||||
// When someone is watching, check again after a certain delay to see if no one is watching (save performance)
|
||||
_is_enable = (_rtmp ? _rtmp->isEnabled() : false) ||
|
||||
(_rtsp ? _rtsp->isEnabled() : false) ||
|
||||
(_ts ? _ts->isEnabled() : false) ||
|
||||
@ -673,7 +706,8 @@ bool MultiMediaSourceMuxer::isEnabled(){
|
||||
_mp4;
|
||||
|
||||
if (_is_enable) {
|
||||
//无人观看时,不刷新计时器,因为无人观看时每次都会检查一遍,所以刷新计数器无意义且浪费cpu
|
||||
// 无人观看时,不刷新计时器,因为无人观看时每次都会检查一遍,所以刷新计数器无意义且浪费cpu [AUTO-TRANSLATED:03ab47cf]
|
||||
// When no one is watching, do not refresh the timer, because each time no one is watching, it will be checked, so refreshing the counter is meaningless and wastes cpu
|
||||
_last_check.resetTime();
|
||||
}
|
||||
}
|
||||
|
@ -41,33 +41,54 @@ public:
|
||||
/**
|
||||
* 设置事件监听器
|
||||
* @param listener 监听器
|
||||
* Set event listener
|
||||
* @param listener Listener
|
||||
|
||||
* [AUTO-TRANSLATED:d829419b]
|
||||
*/
|
||||
void setMediaListener(const std::weak_ptr<MediaSourceEvent> &listener);
|
||||
|
||||
/**
|
||||
* 设置Track就绪事件监听器
|
||||
* @param listener 事件监听器
|
||||
* Set Track ready event listener
|
||||
* @param listener Event listener
|
||||
|
||||
* [AUTO-TRANSLATED:64262ac5]
|
||||
*/
|
||||
void setTrackListener(const std::weak_ptr<Listener> &listener);
|
||||
|
||||
/**
|
||||
* 返回总的消费者个数
|
||||
* Return the total number of consumers
|
||||
|
||||
* [AUTO-TRANSLATED:5eaac131]
|
||||
*/
|
||||
int totalReaderCount() const;
|
||||
|
||||
/**
|
||||
* 判断是否生效(是否正在转其他协议)
|
||||
* Determine whether it is effective (whether it is being converted to another protocol)
|
||||
|
||||
* [AUTO-TRANSLATED:ca92165c]
|
||||
*/
|
||||
bool isEnabled();
|
||||
|
||||
/**
|
||||
* 设置MediaSource时间戳
|
||||
* @param stamp 时间戳
|
||||
* Set MediaSource timestamp
|
||||
* @param stamp Timestamp
|
||||
|
||||
* [AUTO-TRANSLATED:a75cc2fa]
|
||||
*/
|
||||
void setTimeStamp(uint32_t stamp);
|
||||
|
||||
/**
|
||||
* 重置track
|
||||
* Reset track
|
||||
|
||||
* [AUTO-TRANSLATED:95dc0b4f]
|
||||
*/
|
||||
void resetTracks() override;
|
||||
|
||||
@ -77,6 +98,11 @@ public:
|
||||
* 观看总人数
|
||||
* @param sender 事件发送者
|
||||
* @return 观看总人数
|
||||
* Total number of viewers
|
||||
* @param sender Event sender
|
||||
* @return Total number of viewers
|
||||
|
||||
* [AUTO-TRANSLATED:f4d7146c]
|
||||
*/
|
||||
int totalReaderCount(MediaSource &sender) override;
|
||||
|
||||
@ -86,6 +112,13 @@ public:
|
||||
* @param start 开始或停止
|
||||
* @param custom_path 开启录制时,指定自定义路径
|
||||
* @return 是否设置成功
|
||||
* Set recording status
|
||||
* @param type Recording type
|
||||
* @param start Start or stop
|
||||
* @param custom_path Specify a custom path when recording is enabled
|
||||
* @return Whether the setting is successful
|
||||
|
||||
* [AUTO-TRANSLATED:cb1fd8a9]
|
||||
*/
|
||||
bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) override;
|
||||
|
||||
@ -93,6 +126,11 @@ public:
|
||||
* 获取录制状态
|
||||
* @param type 录制类型
|
||||
* @return 录制状态
|
||||
* Get recording status
|
||||
* @param type Recording type
|
||||
* @return Recording status
|
||||
|
||||
* [AUTO-TRANSLATED:798afa71]
|
||||
*/
|
||||
bool isRecording(MediaSource &sender, Recorder::type type) override;
|
||||
|
||||
@ -103,12 +141,24 @@ public:
|
||||
* @param ssrc rtp的ssrc
|
||||
* @param is_udp 是否为udp
|
||||
* @param cb 启动成功或失败回调
|
||||
* Start sending ps-rtp stream
|
||||
* @param dst_url Target ip or domain name
|
||||
* @param dst_port Target port
|
||||
* @param ssrc rtp's ssrc
|
||||
* @param is_udp Whether it is udp
|
||||
* @param cb Start success or failure callback
|
||||
|
||||
* [AUTO-TRANSLATED:620416c2]
|
||||
*/
|
||||
void startSendRtp(MediaSource &sender, const MediaSourceEvent::SendRtpArgs &args, const std::function<void(uint16_t, const toolkit::SockException &)> cb) override;
|
||||
|
||||
/**
|
||||
* 停止ps-rtp发送
|
||||
* @return 是否成功
|
||||
* Stop ps-rtp sending
|
||||
* @return Whether it is successful
|
||||
|
||||
* [AUTO-TRANSLATED:b91e2055]
|
||||
*/
|
||||
bool stopSendRtp(MediaSource &sender, const std::string &ssrc) override;
|
||||
|
||||
@ -116,16 +166,27 @@ public:
|
||||
* 获取所有Track
|
||||
* @param trackReady 是否筛选过滤未就绪的track
|
||||
* @return 所有Track
|
||||
* Get all Tracks
|
||||
* @param trackReady Whether to filter out unready tracks
|
||||
* @return All Tracks
|
||||
|
||||
* [AUTO-TRANSLATED:53755f5d]
|
||||
*/
|
||||
std::vector<Track::Ptr> getMediaTracks(MediaSource &sender, bool trackReady = true) const override;
|
||||
|
||||
/**
|
||||
* 获取所属线程
|
||||
* Get the thread it belongs to
|
||||
|
||||
* [AUTO-TRANSLATED:a4dc847e]
|
||||
*/
|
||||
toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) override;
|
||||
|
||||
/**
|
||||
* 获取本对象
|
||||
* Get this object
|
||||
|
||||
* [AUTO-TRANSLATED:5e119bb3]
|
||||
*/
|
||||
std::shared_ptr<MultiMediaSourceMuxer> getMuxer(MediaSource &sender) const override;
|
||||
|
||||
@ -142,17 +203,29 @@ protected:
|
||||
* 某track已经准备好,其ready()状态返回true,
|
||||
* 此时代表可以获取其例如sps pps等相关信息了
|
||||
* @param track
|
||||
* A certain track is ready, its ready() status returns true,
|
||||
* This means that you can get information such as sps pps, etc.
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:05659d48]
|
||||
*/
|
||||
bool onTrackReady(const Track::Ptr & track) override;
|
||||
|
||||
/**
|
||||
* 所有Track已经准备好,
|
||||
* All Tracks are ready,
|
||||
|
||||
* [AUTO-TRANSLATED:c54d02e2]
|
||||
*/
|
||||
void onAllTrackReady() override;
|
||||
|
||||
/**
|
||||
* 某Track输出frame,在onAllTrackReady触发后才会调用此方法
|
||||
* @param frame
|
||||
* A certain Track outputs a frame, this method will be called after onAllTrackReady is triggered
|
||||
* @param frame
|
||||
|
||||
* [AUTO-TRANSLATED:debbd247]
|
||||
*/
|
||||
bool onTrackFrame(const Frame::Ptr &frame) override;
|
||||
bool onTrackFrame_l(const Frame::Ptr &frame);
|
||||
@ -182,7 +255,8 @@ private:
|
||||
toolkit::EventPoller::Ptr _poller;
|
||||
RingType::Ptr _ring;
|
||||
|
||||
//对象个数统计
|
||||
// 对象个数统计 [AUTO-TRANSLATED:3b43e8c2]
|
||||
// Object count statistics
|
||||
toolkit::ObjectStatistic<MultiMediaSourceMuxer> _statistic;
|
||||
};
|
||||
|
||||
|
@ -15,20 +15,26 @@
|
||||
#include "Util/List.h"
|
||||
|
||||
namespace mediakit {
|
||||
/// 缓存刷新策略类
|
||||
// / 缓存刷新策略类 [AUTO-TRANSLATED:bd941d15]
|
||||
// / Cache refresh strategy class
|
||||
class FlushPolicy {
|
||||
public:
|
||||
bool isFlushAble(bool is_video, bool is_key, uint64_t new_stamp, size_t cache_size);
|
||||
|
||||
private:
|
||||
// 音视频的最后时间戳
|
||||
// 音视频的最后时间戳 [AUTO-TRANSLATED:957d18ed]
|
||||
// Last timestamp of audio and video
|
||||
uint64_t _last_stamp[2] = { 0, 0 };
|
||||
};
|
||||
|
||||
/// 合并写缓存模板
|
||||
/// \tparam packet 包类型
|
||||
/// \tparam policy 刷新缓存策略
|
||||
/// \tparam packet_list 包缓存类型
|
||||
// / 合并写缓存模板 [AUTO-TRANSLATED:25cde944]
|
||||
// / Merge write cache template
|
||||
// / \tparam packet 包类型 [AUTO-TRANSLATED:43085d9b]
|
||||
// / \tparam packet Packet type
|
||||
// / \tparam policy 刷新缓存策略 [AUTO-TRANSLATED:c5ac29a7]
|
||||
// / \tparam policy Refresh cache strategy
|
||||
// / \tparam packet_list 包缓存类型 [AUTO-TRANSLATED:a434e7fe]
|
||||
// / \tparam packet_list Packet cache type
|
||||
template<typename packet, typename policy = FlushPolicy, typename packet_list = toolkit::List<std::shared_ptr<packet> > >
|
||||
class PacketCache {
|
||||
public:
|
||||
@ -42,7 +48,8 @@ public:
|
||||
flush();
|
||||
}
|
||||
|
||||
//追加数据到最后
|
||||
// 追加数据到最后 [AUTO-TRANSLATED:e24ccfb6]
|
||||
// Append data to the end
|
||||
_cache->emplace_back(std::move(pkt));
|
||||
if (key_pos) {
|
||||
_key_pos = key_pos;
|
||||
@ -70,10 +77,14 @@ public:
|
||||
|
||||
private:
|
||||
bool flushImmediatelyWhenCloseMerge() {
|
||||
// 一般的协议关闭合并写时,立即刷新缓存,这样可以减少一帧的延时,但是rtp例外
|
||||
// 因为rtp的包很小,一个RtpPacket包中也不是完整的一帧图像,所以在关闭合并写时,
|
||||
// 还是有必要缓冲一帧的rtp(也就是时间戳相同的rtp)再输出,这样虽然会增加一帧的延时
|
||||
// 但是却对性能提升很大,这样做还是比较划算的
|
||||
// 一般的协议关闭合并写时,立即刷新缓存,这样可以减少一帧的延时,但是rtp例外 [AUTO-TRANSLATED:54eba701]
|
||||
// Generally, when the protocol closes the merge write, the cache is refreshed immediately, which can reduce the delay of one frame, but RTP is an exception.
|
||||
// 因为rtp的包很小,一个RtpPacket包中也不是完整的一帧图像,所以在关闭合并写时, [AUTO-TRANSLATED:b219082d]
|
||||
// Because the RTP packet is very small, and a RtpPacket does not contain a complete frame of image, so when closing the merge write,
|
||||
// 还是有必要缓冲一帧的rtp(也就是时间戳相同的rtp)再输出,这样虽然会增加一帧的延时 [AUTO-TRANSLATED:27c7ee8b]
|
||||
// It is still necessary to buffer one frame of RTP (that is, RTP with the same timestamp) before outputting. Although this will increase the delay of one frame,
|
||||
// 但是却对性能提升很大,这样做还是比较划算的 [AUTO-TRANSLATED:80eab719]
|
||||
// But it greatly improves performance, so it is still worthwhile to do so.
|
||||
|
||||
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
|
||||
GET_CONFIG(int, rtspLowLatency, Rtsp::kLowLatency);
|
||||
|
@ -17,11 +17,14 @@
|
||||
|
||||
namespace mediakit {
|
||||
|
||||
// 从字符串中提取子字符串
|
||||
// 从字符串中提取子字符串 [AUTO-TRANSLATED:8493b6a5]
|
||||
// Extract substring from string
|
||||
std::string findSubString(const char *buf, const char *start, const char *end, size_t buf_size = 0);
|
||||
// 把url解析为主机地址和端口号,兼容ipv4/ipv6/dns
|
||||
// 把url解析为主机地址和端口号,兼容ipv4/ipv6/dns [AUTO-TRANSLATED:0cfa4a6c]
|
||||
// Parse url to host address and port number, compatible with ipv4/ipv6/dns
|
||||
void splitUrl(const std::string &url, std::string &host, uint16_t &port);
|
||||
// 解析proxy url,仅支持http
|
||||
// 解析proxy url,仅支持http [AUTO-TRANSLATED:194b49d7]
|
||||
// Parse proxy url, only supports http
|
||||
void parseProxyUrl(const std::string &proxy_url, std::string &proxy_host, uint16_t &proxy_port, std::string &proxy_auth);
|
||||
|
||||
struct StrCaseCompare {
|
||||
@ -55,53 +58,70 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// rtsp/http/sip解析类
|
||||
// rtsp/http/sip解析类 [AUTO-TRANSLATED:188ca500]
|
||||
// rtsp/http/sip parsing class
|
||||
class Parser {
|
||||
public:
|
||||
// 解析http/rtsp/sip请求,需要确保buf以\0结尾
|
||||
// 解析http/rtsp/sip请求,需要确保buf以\0结尾 [AUTO-TRANSLATED:552953af]
|
||||
// Parse http/rtsp/sip request, ensure buf ends with \0
|
||||
void parse(const char *buf, size_t size);
|
||||
|
||||
// 获取命令字,如GET/POST
|
||||
// 获取命令字,如GET/POST [AUTO-TRANSLATED:34750f3d]
|
||||
// Get command word, such as GET/POST
|
||||
const std::string &method() const;
|
||||
|
||||
// 请求时,获取中间url,不包含?后面的参数
|
||||
// 请求时,获取中间url,不包含?后面的参数 [AUTO-TRANSLATED:c259f1ed]
|
||||
// When requesting, get the middle url, excluding the parameters after ?
|
||||
const std::string &url() const;
|
||||
// 回复时,获取状态码,如200/404
|
||||
// 回复时,获取状态码,如200/404 [AUTO-TRANSLATED:ac3f8ed4]
|
||||
// When replying, get the status code, such as 200/404
|
||||
const std::string &status() const;
|
||||
|
||||
// 获取中间url,包含?后面的参数
|
||||
// 获取中间url,包含?后面的参数 [AUTO-TRANSLATED:ca1fec1a]
|
||||
// Get the middle url, including the parameters after ?
|
||||
std::string fullUrl() const;
|
||||
|
||||
// 请求时,获取协议名,如HTTP/1.1
|
||||
// 请求时,获取协议名,如HTTP/1.1 [AUTO-TRANSLATED:7410fed6]
|
||||
// When requesting, get the protocol name, such as HTTP/1.1
|
||||
const std::string &protocol() const;
|
||||
// 回复时,获取状态字符串,如 OK/Not Found
|
||||
// 回复时,获取状态字符串,如 OK/Not Found [AUTO-TRANSLATED:d245247a]
|
||||
// When replying, get the status string, such as OK/Not Found
|
||||
const std::string &statusStr() const;
|
||||
|
||||
// 根据header key名,获取请求header value值
|
||||
// 根据header key名,获取请求header value值 [AUTO-TRANSLATED:5cbc9ac7]
|
||||
// Get the request header value according to the header key name
|
||||
const std::string &operator[](const char *name) const;
|
||||
|
||||
// 获取http body或sdp
|
||||
// 获取http body或sdp [AUTO-TRANSLATED:d6fd1803]
|
||||
// Get http body or sdp
|
||||
const std::string &content() const;
|
||||
|
||||
// 清空,为了重用
|
||||
// 清空,为了重用 [AUTO-TRANSLATED:cb7a16dd]
|
||||
// Clear, for reuse
|
||||
void clear();
|
||||
|
||||
// 获取?后面的参数
|
||||
// 获取?后面的参数 [AUTO-TRANSLATED:4ada90e1]
|
||||
// Get the parameters after ?
|
||||
const std::string ¶ms() const;
|
||||
|
||||
// 重新设置url
|
||||
// 重新设置url [AUTO-TRANSLATED:4829ba8e]
|
||||
// Reset url
|
||||
void setUrl(std::string url);
|
||||
|
||||
// 重新设置content
|
||||
// 重新设置content [AUTO-TRANSLATED:ac8fc8c0]
|
||||
// Reset content
|
||||
void setContent(std::string content);
|
||||
|
||||
// 获取header列表
|
||||
// 获取header列表 [AUTO-TRANSLATED:90d90b03]
|
||||
// Get header list
|
||||
StrCaseMap &getHeader() const;
|
||||
|
||||
// 获取url参数列表
|
||||
// 获取url参数列表 [AUTO-TRANSLATED:da1df48a]
|
||||
// Get url parameter list
|
||||
StrCaseMap &getUrlArgs() const;
|
||||
|
||||
// 解析?后面的参数
|
||||
// 解析?后面的参数 [AUTO-TRANSLATED:38692051]
|
||||
// Parse the parameters after ?
|
||||
static StrCaseMap parseArgs(const std::string &str, const char *pair_delim = "&", const char *key_delim = "=");
|
||||
|
||||
static std::string mergeUrl(const std::string &base_url, const std::string &path);
|
||||
@ -116,7 +136,8 @@ private:
|
||||
mutable StrCaseMap _url_args;
|
||||
};
|
||||
|
||||
// 解析rtsp url的工具类
|
||||
// 解析rtsp url的工具类 [AUTO-TRANSLATED:0d31ae01]
|
||||
// Utility class for parsing rtsp url
|
||||
class RtspUrl {
|
||||
public:
|
||||
bool _is_ssl;
|
||||
|
@ -10,7 +10,8 @@
|
||||
|
||||
#include "Stamp.h"
|
||||
|
||||
// 时间戳最大允许跳变3秒,主要是防止网络抖动导致的跳变
|
||||
// 时间戳最大允许跳变3秒,主要是防止网络抖动导致的跳变 [AUTO-TRANSLATED:144154de]
|
||||
// Timestamp maximum allowable jump is 3 seconds, mainly to prevent network jitter caused by the jump
|
||||
#define MAX_DELTA_STAMP (3 * 1000)
|
||||
#define STAMP_LOOP_DELTA (60 * 1000)
|
||||
#define MAX_CTS 500
|
||||
@ -21,7 +22,8 @@ using namespace toolkit;
|
||||
namespace mediakit {
|
||||
|
||||
DeltaStamp::DeltaStamp() {
|
||||
// 时间戳最大允许跳跃300ms
|
||||
// 时间戳最大允许跳跃300ms [AUTO-TRANSLATED:2458e61f]
|
||||
// Timestamp maximum allowable jump is 300ms
|
||||
_max_delta = 300;
|
||||
}
|
||||
|
||||
@ -36,7 +38,8 @@ int64_t DeltaStamp::relativeStamp() {
|
||||
|
||||
int64_t DeltaStamp::deltaStamp(int64_t stamp, bool enable_rollback) {
|
||||
if (!_last_stamp) {
|
||||
// 第一次计算时间戳增量,时间戳增量为0
|
||||
// 第一次计算时间戳增量,时间戳增量为0 [AUTO-TRANSLATED:32944bd3]
|
||||
// Calculate the timestamp increment for the first time, the timestamp increment is 0
|
||||
if (stamp) {
|
||||
_last_stamp = stamp;
|
||||
}
|
||||
@ -45,9 +48,11 @@ int64_t DeltaStamp::deltaStamp(int64_t stamp, bool enable_rollback) {
|
||||
|
||||
int64_t ret = stamp - _last_stamp;
|
||||
if (ret >= 0) {
|
||||
// 时间戳增量为正,返回之
|
||||
// 时间戳增量为正,返回之 [AUTO-TRANSLATED:308dfb22]
|
||||
// The timestamp increment is positive, return it
|
||||
_last_stamp = stamp;
|
||||
// 在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP,否则强制相对时间戳加1
|
||||
// 在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP,否则强制相对时间戳加1 [AUTO-TRANSLATED:c78c40d3]
|
||||
// In the live broadcast case, the timestamp increment must not be greater than MAX_DELTA_STAMP, otherwise the relative timestamp is forced to add 1
|
||||
if (ret > _max_delta) {
|
||||
needSync();
|
||||
return 1;
|
||||
@ -55,10 +60,12 @@ int64_t DeltaStamp::deltaStamp(int64_t stamp, bool enable_rollback) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 时间戳增量为负,说明时间戳回环了或回退了
|
||||
// 时间戳增量为负,说明时间戳回环了或回退了 [AUTO-TRANSLATED:fd825d50]
|
||||
// The timestamp increment is negative, indicating that the timestamp has looped or retreated
|
||||
_last_stamp = stamp;
|
||||
if (!enable_rollback || -ret > _max_delta) {
|
||||
// 不允许回退或者回退太多了, 强制时间戳加1
|
||||
// 不允许回退或者回退太多了, 强制时间戳加1 [AUTO-TRANSLATED:152f5ffa]
|
||||
// Not allowed to retreat or retreat too much, force the timestamp to add 1
|
||||
needSync();
|
||||
return 1;
|
||||
}
|
||||
@ -86,16 +93,19 @@ void Stamp::enableRollback(bool flag) {
|
||||
_enable_rollback = flag;
|
||||
}
|
||||
|
||||
// 限制dts回退
|
||||
// 限制dts回退 [AUTO-TRANSLATED:6bc53b31]
|
||||
// Limit dts retreat
|
||||
void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, bool modifyStamp) {
|
||||
revise_l(dts, pts, dts_out, pts_out, modifyStamp);
|
||||
if (_playback) {
|
||||
// 回放允许时间戳回退
|
||||
// 回放允许时间戳回退 [AUTO-TRANSLATED:5d822118]
|
||||
// Playback allows timestamp rollback
|
||||
return;
|
||||
}
|
||||
|
||||
if (dts_out < _last_dts_out) {
|
||||
// WarnL << "dts回退:" << dts_out << " < " << _last_dts_out;
|
||||
// WarnL << "dts回退:" << dts_out << " < " << _last_dts_out; [AUTO-TRANSLATED:c36316f5]
|
||||
// WarnL << "dts rollback:" << dts_out << " < " << _last_dts_out;
|
||||
dts_out = _last_dts_out;
|
||||
pts_out = _last_pts_out;
|
||||
return;
|
||||
@ -104,27 +114,34 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,
|
||||
_last_pts_out = pts_out;
|
||||
}
|
||||
|
||||
// 音视频时间戳同步
|
||||
// 音视频时间戳同步 [AUTO-TRANSLATED:58f1e95c]
|
||||
// Audio and video timestamp synchronization
|
||||
void Stamp::revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, bool modifyStamp) {
|
||||
revise_l2(dts, pts, dts_out, pts_out, modifyStamp);
|
||||
if (!_sync_master || modifyStamp || _playback) {
|
||||
// 自动生成时间戳或回放或同步完毕
|
||||
// 自动生成时间戳或回放或同步完毕 [AUTO-TRANSLATED:a0b8f8bd]
|
||||
// Automatically generate timestamps or playback or synchronization is complete
|
||||
return;
|
||||
}
|
||||
|
||||
// 需要同步时间戳
|
||||
// 需要同步时间戳 [AUTO-TRANSLATED:af93e8f8]
|
||||
// Need to synchronize timestamps
|
||||
if (_sync_master && _sync_master->_last_dts_in && (_need_sync || _sync_master->_need_sync)) {
|
||||
// 音视频dts当前时间差
|
||||
// 音视频dts当前时间差 [AUTO-TRANSLATED:716468a6]
|
||||
// Audio and video dts current time difference
|
||||
int64_t dts_diff = _last_dts_in - _sync_master->_last_dts_in;
|
||||
if (ABS(dts_diff) < 5000) {
|
||||
// 如果绝对时间戳小于5秒,那么说明他们的起始时间戳是一致的,那么强制同步
|
||||
// 如果绝对时间戳小于5秒,那么说明他们的起始时间戳是一致的,那么强制同步 [AUTO-TRANSLATED:5d11ef6a]
|
||||
// If the absolute timestamp is less than 5 seconds, then it means that their starting timestamps are consistent, then force synchronization
|
||||
auto target_stamp = _sync_master->_relative_stamp + dts_diff;
|
||||
if (target_stamp > _relative_stamp || _enable_rollback) {
|
||||
// 强制同步后,时间戳增加跳跃了,或允许回退
|
||||
// 强制同步后,时间戳增加跳跃了,或允许回退 [AUTO-TRANSLATED:805424a9]
|
||||
// After forced synchronization, the timestamp increases jump, or allows rollback
|
||||
TraceL << "Relative stamp changed: " << _relative_stamp << " -> " << target_stamp;
|
||||
_relative_stamp = target_stamp;
|
||||
} else {
|
||||
// 不允许回退, 则让另外一个Track的时间戳增长
|
||||
// 不允许回退, 则让另外一个Track的时间戳增长 [AUTO-TRANSLATED:428e8ce2]
|
||||
// Not allowed to rollback, then let the timestamp of the other Track increase
|
||||
target_stamp = _relative_stamp - dts_diff;
|
||||
TraceL << "Relative stamp changed: " << _sync_master->_relative_stamp << " -> " << target_stamp;
|
||||
_sync_master->_relative_stamp = target_stamp;
|
||||
@ -135,15 +152,18 @@ void Stamp::revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_ou
|
||||
}
|
||||
}
|
||||
|
||||
// 求取相对时间戳
|
||||
// 求取相对时间戳 [AUTO-TRANSLATED:122da805]
|
||||
// Obtain the relative timestamp
|
||||
void Stamp::revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, bool modifyStamp) {
|
||||
if (!pts) {
|
||||
// 没有播放时间戳,使其赋值为解码时间戳
|
||||
// 没有播放时间戳,使其赋值为解码时间戳 [AUTO-TRANSLATED:9ee71899]
|
||||
// There is no playback timestamp, set it to the decoding timestamp
|
||||
pts = dts;
|
||||
}
|
||||
|
||||
if (_playback) {
|
||||
// 这是点播
|
||||
// 这是点播 [AUTO-TRANSLATED:f11fd173]
|
||||
// This is on-demand
|
||||
dts_out = dts;
|
||||
pts_out = pts;
|
||||
_relative_stamp = dts_out;
|
||||
@ -151,13 +171,16 @@ void Stamp::revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_o
|
||||
return;
|
||||
}
|
||||
|
||||
// pts和dts的差值
|
||||
// pts和dts的差值 [AUTO-TRANSLATED:3b145073]
|
||||
// The difference between pts and dts
|
||||
int64_t pts_dts_diff = pts - dts;
|
||||
|
||||
if (_last_dts_in != dts) {
|
||||
// 时间戳发生变更
|
||||
// 时间戳发生变更 [AUTO-TRANSLATED:7344315c]
|
||||
// Timestamp changed
|
||||
if (modifyStamp) {
|
||||
// 内部自己生产时间戳
|
||||
// 内部自己生产时间戳 [AUTO-TRANSLATED:fae889e0]
|
||||
// Internal production of timestamps
|
||||
_relative_stamp = _ticker.elapsedTime();
|
||||
} else {
|
||||
_relative_stamp += deltaStamp(dts, _enable_rollback);
|
||||
@ -166,9 +189,11 @@ void Stamp::revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_o
|
||||
}
|
||||
dts_out = _relative_stamp;
|
||||
|
||||
//////////////以下是播放时间戳的计算//////////////////
|
||||
// ////////////以下是播放时间戳的计算////////////////// [AUTO-TRANSLATED:6c4a56a7]
|
||||
// ////////////The following is the calculation of the playback timestamp//////////////////
|
||||
if (ABS(pts_dts_diff) > MAX_CTS) {
|
||||
// 如果差值太大,则认为由于回环导致时间戳错乱了
|
||||
// 如果差值太大,则认为由于回环导致时间戳错乱了 [AUTO-TRANSLATED:1a11b5f3]
|
||||
// If the difference is too large, it is considered that the timestamp is messed up due to looping
|
||||
pts_dts_diff = 0;
|
||||
}
|
||||
|
||||
@ -186,89 +211,115 @@ int64_t Stamp::getRelativeStamp() const {
|
||||
bool DtsGenerator::getDts(uint64_t pts, uint64_t &dts) {
|
||||
bool ret = false;
|
||||
if (pts == _last_pts) {
|
||||
// pts未变,说明dts也不会变,返回上次dts
|
||||
// pts未变,说明dts也不会变,返回上次dts [AUTO-TRANSLATED:dc0972e0]
|
||||
// pts does not change, indicating that dts will not change, return the last dts
|
||||
if (_last_dts) {
|
||||
dts = _last_dts;
|
||||
ret = true;
|
||||
}
|
||||
} else {
|
||||
// pts变了,尝试计算dts
|
||||
// pts变了,尝试计算dts [AUTO-TRANSLATED:f527d0f6]
|
||||
// pts changed, try to calculate dts
|
||||
ret = getDts_l(pts, dts);
|
||||
if (ret) {
|
||||
// 获取到了dts,保存本次结果
|
||||
// 获取到了dts,保存本次结果 [AUTO-TRANSLATED:d6a5ce6d]
|
||||
// Get the dts, save the current result
|
||||
_last_dts = dts;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
// pts排序列队长度还不知道,也就是不知道有没有B帧,
|
||||
// 那么先强制dts == pts,这样可能导致有B帧的情况下,起始画面有几帧回退
|
||||
// pts排序列队长度还不知道,也就是不知道有没有B帧, [AUTO-TRANSLATED:e5ad4327]
|
||||
// The pts sorting queue length is not yet known, that is, it is not known whether there is a B frame,
|
||||
// 那么先强制dts == pts,这样可能导致有B帧的情况下,起始画面有几帧回退 [AUTO-TRANSLATED:74c97de1]
|
||||
// Then force dts == pts first, which may cause the starting picture to have a few frames rollback in the case of B frames
|
||||
dts = pts;
|
||||
}
|
||||
|
||||
// 记录上次pts
|
||||
// 记录上次pts [AUTO-TRANSLATED:4ecd474b]
|
||||
// Record the last pts
|
||||
_last_pts = pts;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 该算法核心思想是对pts进行排序,排序好的pts就是dts。
|
||||
// 排序有一定的滞后性,那么需要加上排序导致的时间戳偏移量
|
||||
// 该算法核心思想是对pts进行排序,排序好的pts就是dts。 [AUTO-TRANSLATED:efb36e04]
|
||||
// The core idea of this algorithm is to sort the pts, and the sorted pts is the dts.
|
||||
// 排序有一定的滞后性,那么需要加上排序导致的时间戳偏移量 [AUTO-TRANSLATED:5ada843a]
|
||||
// Sorting has a certain lag, so it is necessary to add the timestamp offset caused by sorting
|
||||
bool DtsGenerator::getDts_l(uint64_t pts, uint64_t &dts) {
|
||||
if (_sorter_max_size == 1) {
|
||||
// 没有B帧,dts就等于pts
|
||||
// 没有B帧,dts就等于pts [AUTO-TRANSLATED:9cfae4ea]
|
||||
// There is no B frame, dts is equal to pts
|
||||
dts = pts;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_sorter_max_size) {
|
||||
// 尚未计算出pts排序列队长度(也就是P帧间B帧个数)
|
||||
// 尚未计算出pts排序列队长度(也就是P帧间B帧个数) [AUTO-TRANSLATED:8bedb754]
|
||||
// The length of the pts sorting queue (that is, the number of B frames between P frames) has not been calculated yet
|
||||
if (pts > _last_max_pts) {
|
||||
// pts时间戳增加了,那么说明这帧画面不是B帧(说明是P帧或关键帧)
|
||||
// pts时间戳增加了,那么说明这帧画面不是B帧(说明是P帧或关键帧) [AUTO-TRANSLATED:4c5ef2b8]
|
||||
// The pts timestamp has increased, which means that this frame is not a B frame (it means it is a P frame or a key frame)
|
||||
if (_frames_since_last_max_pts && _count_sorter_max_size++ > 0) {
|
||||
// 已经出现多次非B帧的情况,那么我们就能知道P帧间B帧的个数
|
||||
// 已经出现多次非B帧的情况,那么我们就能知道P帧间B帧的个数 [AUTO-TRANSLATED:fd747b3c]
|
||||
// There have been multiple non-B frames, so we can know the number of B frames between P frames
|
||||
_sorter_max_size = _frames_since_last_max_pts;
|
||||
// 我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计)
|
||||
// 我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计) [AUTO-TRANSLATED:66c0cc14]
|
||||
// We record the time interval between P frames (that is, the cumulative increment of multiple B frame timestamps)
|
||||
_dts_pts_offset = (pts - _last_max_pts);
|
||||
// 除以2,防止dts大于pts
|
||||
// 除以2,防止dts大于pts [AUTO-TRANSLATED:52b5b3ab]
|
||||
// Divide by 2 to prevent dts from being greater than pts
|
||||
_dts_pts_offset /= 2;
|
||||
}
|
||||
// 遇到P帧或关键帧,连续B帧计数清零
|
||||
// 遇到P帧或关键帧,连续B帧计数清零 [AUTO-TRANSLATED:537bb54d]
|
||||
// When encountering a P frame or a key frame, the continuous B frame count is cleared
|
||||
_frames_since_last_max_pts = 0;
|
||||
// 记录上次非B帧的pts时间戳(同时也是dts),用于统计连续B帧时间戳增量
|
||||
// 记录上次非B帧的pts时间戳(同时也是dts),用于统计连续B帧时间戳增量 [AUTO-TRANSLATED:194f8cdb]
|
||||
// Record the pts timestamp of the last non-B frame (which is also dts), used to count the continuous B frame timestamp increment
|
||||
_last_max_pts = pts;
|
||||
}
|
||||
// 如果pts时间戳小于上一个P帧,那么断定这个是B帧,我们记录B帧连续个数
|
||||
// 如果pts时间戳小于上一个P帧,那么断定这个是B帧,我们记录B帧连续个数 [AUTO-TRANSLATED:1a7e33e2]
|
||||
// If the pts timestamp is less than the previous P frame, then it is determined that this is a B frame, and we record the number of consecutive B frames
|
||||
++_frames_since_last_max_pts;
|
||||
}
|
||||
|
||||
// pts放入排序缓存列队,缓存列队最大等于连续B帧个数
|
||||
// pts放入排序缓存列队,缓存列队最大等于连续B帧个数 [AUTO-TRANSLATED:ff598a97]
|
||||
// Put pts into the sorting cache queue, the maximum cache queue is equal to the number of consecutive B frames
|
||||
_pts_sorter.emplace(pts);
|
||||
|
||||
if (_sorter_max_size && _pts_sorter.size() > _sorter_max_size) {
|
||||
// 如果启用了pts排序(意味着存在B帧),并且pts排序缓存列队长度大于连续B帧个数,
|
||||
// 意味着后续的pts都会比最早的pts大,那么说明可以取出最早的pts了,这个pts将当做该帧的dts基准
|
||||
// 如果启用了pts排序(意味着存在B帧),并且pts排序缓存列队长度大于连续B帧个数, [AUTO-TRANSLATED:002c0d03]
|
||||
// If pts sorting is enabled (meaning there are B frames), and the length of the pts sorting cache queue is greater than the number of consecutive B frames,
|
||||
// 意味着后续的pts都会比最早的pts大,那么说明可以取出最早的pts了,这个pts将当做该帧的dts基准 [AUTO-TRANSLATED:86b8f679]
|
||||
// It means that the subsequent pts will be larger than the earliest pts, which means that the earliest pts can be taken out, and this pts will be used as the dts baseline for this frame
|
||||
auto it = _pts_sorter.begin();
|
||||
|
||||
// 由于该pts是前面偏移了个_sorter_max_size帧的pts(也就是那帧画面的dts),
|
||||
// 那么我们加上时间戳偏移量,基本等于该帧的dts
|
||||
// 由于该pts是前面偏移了个_sorter_max_size帧的pts(也就是那帧画面的dts), [AUTO-TRANSLATED:eb3657aa]
|
||||
// Since this pts is the pts of the previous _sorter_max_size frames (that is, the dts of that frame),
|
||||
// 那么我们加上时间戳偏移量,基本等于该帧的dts [AUTO-TRANSLATED:245aac6e]
|
||||
// Then we add the timestamp offset, which is basically equal to the dts of this frame
|
||||
dts = *it + _dts_pts_offset;
|
||||
if (dts > pts) {
|
||||
// dts不能大于pts(基本不可能到达这个逻辑)
|
||||
// dts不能大于pts(基本不可能到达这个逻辑) [AUTO-TRANSLATED:847c4531]
|
||||
// dts cannot be greater than pts (it is basically impossible to reach this logic)
|
||||
dts = pts;
|
||||
}
|
||||
|
||||
// pts排序缓存出列
|
||||
// pts排序缓存出列 [AUTO-TRANSLATED:8b580191]
|
||||
// pts sorting cache dequeue
|
||||
_pts_sorter.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 排序缓存尚未满
|
||||
// 排序缓存尚未满 [AUTO-TRANSLATED:3f502460]
|
||||
// The sorting cache is not full yet
|
||||
return false;
|
||||
}
|
||||
|
||||
void NtpStamp::setNtpStamp(uint32_t rtp_stamp, uint64_t ntp_stamp_ms) {
|
||||
if (!ntp_stamp_ms || !rtp_stamp) {
|
||||
// 实测发现有些rtsp服务器发送的rtp时间戳和ntp时间戳一直为0
|
||||
// 实测发现有些rtsp服务器发送的rtp时间戳和ntp时间戳一直为0 [AUTO-TRANSLATED:d3c200fc]
|
||||
// It has been found that some rtsp servers send rtp timestamps and ntp timestamps that are always 0
|
||||
WarnL << "Invalid sender report rtcp, ntp_stamp_ms = " << ntp_stamp_ms << ", rtp_stamp = " << rtp_stamp;
|
||||
return;
|
||||
}
|
||||
@ -289,48 +340,59 @@ uint64_t NtpStamp::getNtpStamp(uint32_t rtp_stamp, uint32_t sample_rate) {
|
||||
|
||||
uint64_t NtpStamp::getNtpStampUS(uint32_t rtp_stamp, uint32_t sample_rate) {
|
||||
if (!_last_ntp_stamp_us) {
|
||||
// 尚未收到sender report rtcp包,那么赋值为本地系统时间戳吧
|
||||
// 尚未收到sender report rtcp包,那么赋值为本地系统时间戳吧 [AUTO-TRANSLATED:c9056069]
|
||||
// The sender report rtcp packet has not been received yet, so assign it to the local system timestamp
|
||||
update(rtp_stamp, getCurrentMicrosecond(true));
|
||||
}
|
||||
|
||||
// rtp时间戳正增长
|
||||
// rtp时间戳正增长 [AUTO-TRANSLATED:4d3c87d1]
|
||||
// The rtp timestamp is increasing
|
||||
if (rtp_stamp >= _last_rtp_stamp) {
|
||||
auto diff_us = static_cast<int64_t>((rtp_stamp - _last_rtp_stamp) / (sample_rate / 1000000.0f));
|
||||
if (diff_us < MAX_DELTA_STAMP * 1000) {
|
||||
// 时间戳正常增长
|
||||
// 时间戳正常增长 [AUTO-TRANSLATED:db60e84a]
|
||||
// The timestamp is increasing normally
|
||||
update(rtp_stamp, _last_ntp_stamp_us + diff_us);
|
||||
return _last_ntp_stamp_us;
|
||||
}
|
||||
|
||||
// 时间戳大幅跳跃
|
||||
// 时间戳大幅跳跃 [AUTO-TRANSLATED:c8585a51]
|
||||
// The timestamp jumps significantly
|
||||
uint64_t loop_delta_hz = STAMP_LOOP_DELTA * sample_rate / 1000;
|
||||
if (_last_rtp_stamp < loop_delta_hz && rtp_stamp > UINT32_MAX - loop_delta_hz) {
|
||||
// 应该是rtp时间戳溢出+乱序
|
||||
// 应该是rtp时间戳溢出+乱序 [AUTO-TRANSLATED:13529fd6]
|
||||
// It should be rtp timestamp overflow + out of order
|
||||
uint64_t max_rtp_us = uint64_t(UINT32_MAX) * 1000000 / sample_rate;
|
||||
return _last_ntp_stamp_us + diff_us - max_rtp_us;
|
||||
}
|
||||
// 不明原因的时间戳大幅跳跃,直接返回上次值
|
||||
// 不明原因的时间戳大幅跳跃,直接返回上次值 [AUTO-TRANSLATED:952b769c]
|
||||
// The timestamp jumps significantly for unknown reasons, directly return the last value
|
||||
WarnL << "rtp stamp abnormal increased:" << _last_rtp_stamp << " -> " << rtp_stamp;
|
||||
update(rtp_stamp, _last_ntp_stamp_us);
|
||||
return _last_ntp_stamp_us;
|
||||
}
|
||||
|
||||
// rtp时间戳负增长
|
||||
// rtp时间戳负增长 [AUTO-TRANSLATED:54a7f797]
|
||||
// The rtp timestamp is decreasing
|
||||
auto diff_us = static_cast<int64_t>((_last_rtp_stamp - rtp_stamp) / (sample_rate / 1000000.0f));
|
||||
if (diff_us < MAX_DELTA_STAMP * 1000) {
|
||||
// 正常范围的时间戳回退,说明收到rtp乱序了
|
||||
// 正常范围的时间戳回退,说明收到rtp乱序了 [AUTO-TRANSLATED:f691d5bf]
|
||||
// The timestamp retreats within the normal range, indicating that the rtp is out of order
|
||||
return _last_ntp_stamp_us - diff_us;
|
||||
}
|
||||
|
||||
// 时间戳大幅度回退
|
||||
// 时间戳大幅度回退 [AUTO-TRANSLATED:0ad69100]
|
||||
// The timestamp retreats significantly
|
||||
uint64_t loop_delta_hz = STAMP_LOOP_DELTA * sample_rate / 1000;
|
||||
if (rtp_stamp < loop_delta_hz && _last_rtp_stamp > UINT32_MAX - loop_delta_hz) {
|
||||
// 确定是时间戳溢出
|
||||
// 确定是时间戳溢出 [AUTO-TRANSLATED:322274c3]
|
||||
// Determine if it is a timestamp overflow
|
||||
uint64_t max_rtp_us = uint64_t(UINT32_MAX) * 1000000 / sample_rate;
|
||||
update(rtp_stamp, _last_ntp_stamp_us + (max_rtp_us - diff_us));
|
||||
return _last_ntp_stamp_us;
|
||||
}
|
||||
// 不明原因的时间戳回退,直接返回上次值
|
||||
// 不明原因的时间戳回退,直接返回上次值 [AUTO-TRANSLATED:c5105c14]
|
||||
// Timestamp rollback for unknown reasons, return the last value directly
|
||||
WarnL << "rtp stamp abnormal reduced:" << _last_rtp_stamp << " -> " << rtp_stamp;
|
||||
update(rtp_stamp, _last_ntp_stamp_us);
|
||||
return _last_ntp_stamp_us;
|
||||
|
@ -27,12 +27,19 @@ public:
|
||||
* @param stamp 绝对时间戳
|
||||
* @param enable_rollback 是否允许相当时间戳回退
|
||||
* @return 时间戳增量
|
||||
* Calculate the timestamp increment
|
||||
* @param stamp Absolute timestamp
|
||||
* @param enable_rollback Whether to allow the timestamp to roll back
|
||||
* @return Timestamp increment
|
||||
|
||||
* [AUTO-TRANSLATED:e8d21dcd]
|
||||
*/
|
||||
int64_t deltaStamp(int64_t stamp, bool enable_rollback = true);
|
||||
int64_t relativeStamp(int64_t stamp, bool enable_rollback = true);
|
||||
int64_t relativeStamp();
|
||||
|
||||
// 设置最大允许回退或跳跃幅度
|
||||
// 设置最大允许回退或跳跃幅度 [AUTO-TRANSLATED:e5b44ede]
|
||||
// Set the maximum allowed rollback or jump amplitude
|
||||
void setMaxDelta(size_t max_delta);
|
||||
|
||||
protected:
|
||||
@ -44,8 +51,10 @@ protected:
|
||||
int64_t _relative_stamp = 0;
|
||||
};
|
||||
|
||||
//该类解决时间戳回环、回退问题
|
||||
//计算相对时间戳或者产生平滑时间戳
|
||||
// 该类解决时间戳回环、回退问题 [AUTO-TRANSLATED:b442692c]
|
||||
// This class solves the problem of timestamp loopback and rollback
|
||||
// 计算相对时间戳或者产生平滑时间戳 [AUTO-TRANSLATED:0deabd6e]
|
||||
// Calculate the relative timestamp or generate a smooth timestamp
|
||||
class Stamp : public DeltaStamp{
|
||||
public:
|
||||
/**
|
||||
@ -55,43 +64,72 @@ public:
|
||||
* @param dts_out 输出dts
|
||||
* @param pts_out 输出pts
|
||||
* @param modifyStamp 是否用系统时间戳覆盖
|
||||
* Get the relative timestamp, which also implements audio and video synchronization, limits dts rollback, etc.
|
||||
* @param dts Input dts, if it is 0, it will be generated according to the system timestamp
|
||||
* @param pts Input pts, if it is 0, it is equal to dts
|
||||
* @param dts_out Output dts
|
||||
* @param pts_out Output pts
|
||||
* @param modifyStamp Whether to overwrite with the system timestamp
|
||||
|
||||
* [AUTO-TRANSLATED:0b939dc5]
|
||||
*/
|
||||
void revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false);
|
||||
|
||||
/**
|
||||
* 再设置相对时间戳,用于seek用
|
||||
* @param relativeStamp 相对时间戳
|
||||
* Set the relative timestamp again, used for seek
|
||||
* @param relativeStamp Relative timestamp
|
||||
|
||||
* [AUTO-TRANSLATED:fc087399]
|
||||
*/
|
||||
void setRelativeStamp(int64_t relativeStamp);
|
||||
|
||||
/**
|
||||
* 获取当前相对时间戳
|
||||
* @return
|
||||
* Get the current relative timestamp
|
||||
* @return
|
||||
|
||||
* [AUTO-TRANSLATED:7ca29fde]
|
||||
*/
|
||||
int64_t getRelativeStamp() const ;
|
||||
|
||||
/**
|
||||
* 设置是否为回放模式,回放模式运行时间戳回退
|
||||
* @param playback 是否为回放模式
|
||||
* Set whether it is playback mode, playback mode allows timestamp rollback
|
||||
* @param playback Whether it is playback mode
|
||||
|
||||
* [AUTO-TRANSLATED:ffe5e40b]
|
||||
*/
|
||||
void setPlayBack(bool playback = true);
|
||||
|
||||
/**
|
||||
* 音视频同步用,音频应该同步于视频(只修改音频时间戳)
|
||||
* 因为音频时间戳修改后不影响播放速度
|
||||
* Used for audio and video synchronization, audio should be synchronized with video (only modify audio timestamp)
|
||||
* Because modifying the audio timestamp does not affect the playback speed
|
||||
|
||||
* [AUTO-TRANSLATED:7ac41a76]
|
||||
*/
|
||||
void syncTo(Stamp &other);
|
||||
|
||||
/**
|
||||
* 是否允许时间戳回退
|
||||
* Whether to allow timestamp rollback
|
||||
|
||||
* [AUTO-TRANSLATED:1d32f7e3]
|
||||
*/
|
||||
void enableRollback(bool flag);
|
||||
|
||||
private:
|
||||
//主要实现音视频时间戳同步功能
|
||||
// 主要实现音视频时间戳同步功能 [AUTO-TRANSLATED:45863fce]
|
||||
// Mainly implements audio and video timestamp synchronization function
|
||||
void revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false);
|
||||
|
||||
//主要实现获取相对时间戳功能
|
||||
// 主要实现获取相对时间戳功能 [AUTO-TRANSLATED:4e042942]
|
||||
// Mainly implements the function of obtaining the relative timestamp
|
||||
void revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false);
|
||||
|
||||
void needSync() override;
|
||||
@ -99,7 +137,8 @@ private:
|
||||
private:
|
||||
bool _playback = false;
|
||||
bool _need_sync = false;
|
||||
// 默认不允许时间戳回滚
|
||||
// 默认不允许时间戳回滚 [AUTO-TRANSLATED:0163ff03]
|
||||
// Default does not allow timestamp rollback
|
||||
bool _enable_rollback = false;
|
||||
int64_t _relative_stamp = 0;
|
||||
int64_t _last_dts_in = 0;
|
||||
@ -109,8 +148,10 @@ private:
|
||||
Stamp *_sync_master = nullptr;
|
||||
};
|
||||
|
||||
//dts生成器,
|
||||
//pts排序后就是dts
|
||||
// dts生成器, [AUTO-TRANSLATED:d8a794a2]
|
||||
// dts generator,
|
||||
// pts排序后就是dts [AUTO-TRANSLATED:439ac368]
|
||||
// pts after sorting is dts
|
||||
class DtsGenerator{
|
||||
public:
|
||||
bool getDts(uint64_t pts, uint64_t &dts);
|
||||
|
@ -39,7 +39,8 @@ bool loadIniConfig(const char *ini_path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
////////////广播名称///////////
|
||||
// //////////广播名称/////////// [AUTO-TRANSLATED:439b2d74]
|
||||
// //////////Broadcast Name///////////
|
||||
namespace Broadcast {
|
||||
const string kBroadcastMediaChanged = "kBroadcastMediaChanged";
|
||||
const string kBroadcastRecordMP4 = "kBroadcastRecordMP4";
|
||||
@ -68,7 +69,8 @@ const string kBroadcastPlayerCountChanged = "kBroadcastPlayerCountChanged";
|
||||
|
||||
} // namespace Broadcast
|
||||
|
||||
// 通用配置项目
|
||||
// 通用配置项目 [AUTO-TRANSLATED:ca344202]
|
||||
// General Configuration Items
|
||||
namespace General {
|
||||
#define GENERAL_FIELD "general."
|
||||
const string kMediaServerId = GENERAL_FIELD "mediaServerId";
|
||||
@ -165,7 +167,8 @@ static onceToken token([]() {
|
||||
});
|
||||
} // !Protocol
|
||||
|
||||
////////////HTTP配置///////////
|
||||
// //////////HTTP配置/////////// [AUTO-TRANSLATED:a281d694]
|
||||
// //////////HTTP Configuration///////////
|
||||
namespace Http {
|
||||
#define HTTP_FIELD "http."
|
||||
const string kSendBufSize = HTTP_FIELD "sendBufSize";
|
||||
@ -208,7 +211,8 @@ static onceToken token([]() {
|
||||
|
||||
} // namespace Http
|
||||
|
||||
////////////SHELL配置///////////
|
||||
// //////////SHELL配置/////////// [AUTO-TRANSLATED:f023ec45]
|
||||
// //////////SHELL Configuration///////////
|
||||
namespace Shell {
|
||||
#define SHELL_FIELD "shell."
|
||||
const string kMaxReqSize = SHELL_FIELD "maxReqSize";
|
||||
@ -216,7 +220,8 @@ const string kMaxReqSize = SHELL_FIELD "maxReqSize";
|
||||
static onceToken token([]() { mINI::Instance()[kMaxReqSize] = 1024; });
|
||||
} // namespace Shell
|
||||
|
||||
////////////RTSP服务器配置///////////
|
||||
// //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981]
|
||||
// //////////RTSP Server Configuration///////////
|
||||
namespace Rtsp {
|
||||
#define RTSP_FIELD "rtsp."
|
||||
const string kAuthBasic = RTSP_FIELD "authBasic";
|
||||
@ -227,7 +232,8 @@ const string kLowLatency = RTSP_FIELD"lowLatency";
|
||||
const string kRtpTransportType = RTSP_FIELD"rtpTransportType";
|
||||
|
||||
static onceToken token([]() {
|
||||
// 默认Md5方式认证
|
||||
// 默认Md5方式认证 [AUTO-TRANSLATED:6155d989]
|
||||
// Default Md5 authentication
|
||||
mINI::Instance()[kAuthBasic] = 0;
|
||||
mINI::Instance()[kHandshakeSecond] = 15;
|
||||
mINI::Instance()[kKeepAliveSecond] = 15;
|
||||
@ -237,7 +243,8 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace Rtsp
|
||||
|
||||
////////////RTMP服务器配置///////////
|
||||
// //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f]
|
||||
// //////////RTMP Server Configuration///////////
|
||||
namespace Rtmp {
|
||||
#define RTMP_FIELD "rtmp."
|
||||
const string kHandshakeSecond = RTMP_FIELD "handshakeSecond";
|
||||
@ -253,13 +260,16 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace Rtmp
|
||||
|
||||
////////////RTP配置///////////
|
||||
// //////////RTP配置/////////// [AUTO-TRANSLATED:23cbcb86]
|
||||
// //////////RTP Configuration///////////
|
||||
namespace Rtp {
|
||||
#define RTP_FIELD "rtp."
|
||||
// RTP打包最大MTU,公网情况下更小
|
||||
// RTP打包最大MTU,公网情况下更小 [AUTO-TRANSLATED:869f5c4b]
|
||||
// Maximum RTP packet MTU, smaller for public networks
|
||||
const string kVideoMtuSize = RTP_FIELD "videoMtuSize";
|
||||
const string kAudioMtuSize = RTP_FIELD "audioMtuSize";
|
||||
// rtp包最大长度限制,单位是KB
|
||||
// rtp包最大长度限制,单位是KB [AUTO-TRANSLATED:aee4bffc]
|
||||
// Maximum RTP packet length limit, in KB
|
||||
const string kRtpMaxSize = RTP_FIELD "rtpMaxSize";
|
||||
const string kLowLatency = RTP_FIELD "lowLatency";
|
||||
const string kH264StapA = RTP_FIELD "h264_stap_a";
|
||||
@ -273,14 +283,18 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace Rtp
|
||||
|
||||
////////////组播配置///////////
|
||||
// //////////组播配置/////////// [AUTO-TRANSLATED:dc39b9d6]
|
||||
// //////////Multicast Configuration///////////
|
||||
namespace MultiCast {
|
||||
#define MULTI_FIELD "multicast."
|
||||
// 组播分配起始地址
|
||||
// 组播分配起始地址 [AUTO-TRANSLATED:069db91d]
|
||||
// Multicast allocation starting address
|
||||
const string kAddrMin = MULTI_FIELD "addrMin";
|
||||
// 组播分配截止地址
|
||||
// 组播分配截止地址 [AUTO-TRANSLATED:6d3fc54c]
|
||||
// Multicast allocation ending address
|
||||
const string kAddrMax = MULTI_FIELD "addrMax";
|
||||
// 组播TTL
|
||||
// 组播TTL [AUTO-TRANSLATED:c7c5339c]
|
||||
// Multicast TTL
|
||||
const string kUdpTTL = MULTI_FIELD "udpTTL";
|
||||
|
||||
static onceToken token([]() {
|
||||
@ -290,7 +304,8 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace MultiCast
|
||||
|
||||
////////////录像配置///////////
|
||||
// //////////录像配置/////////// [AUTO-TRANSLATED:19de3e96]
|
||||
// //////////Recording Configuration///////////
|
||||
namespace Record {
|
||||
#define RECORD_FIELD "record."
|
||||
const string kAppName = RECORD_FIELD "appName";
|
||||
@ -310,7 +325,8 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace Record
|
||||
|
||||
////////////HLS相关配置///////////
|
||||
// //////////HLS相关配置/////////// [AUTO-TRANSLATED:873cc84c]
|
||||
// //////////HLS Related Configuration///////////
|
||||
namespace Hls {
|
||||
#define HLS_FIELD "hls."
|
||||
const string kSegmentDuration = HLS_FIELD "segDur";
|
||||
@ -336,7 +352,8 @@ static onceToken token([]() {
|
||||
});
|
||||
} // namespace Hls
|
||||
|
||||
////////////Rtp代理相关配置///////////
|
||||
// //////////Rtp代理相关配置/////////// [AUTO-TRANSLATED:7b285587]
|
||||
// //////////Rtp Proxy Related Configuration///////////
|
||||
namespace RtpProxy {
|
||||
#define RTP_PROXY_FIELD "rtp_proxy."
|
||||
const string kDumpDir = RTP_PROXY_FIELD "dumpDir";
|
||||
@ -441,7 +458,8 @@ public:
|
||||
MemThreadInfo(bool is_thread_local) {
|
||||
_is_thread_local = is_thread_local;
|
||||
if (_is_thread_local) {
|
||||
// 确保所有线程退出后才能释放全局内存统计器
|
||||
// 确保所有线程退出后才能释放全局内存统计器 [AUTO-TRANSLATED:edb51704]
|
||||
// Ensure that all threads exit before releasing the global memory statistics
|
||||
total_mem = Instance(false);
|
||||
}
|
||||
// printf("%s %d\r\n", __FUNCTION__, (int) _is_thread_local);
|
||||
@ -491,7 +509,8 @@ private:
|
||||
MemThreadInfo *ptr;
|
||||
};
|
||||
|
||||
// 该变量主要确保线程退出后才能释放MemThreadInfo变量
|
||||
// 该变量主要确保线程退出后才能释放MemThreadInfo变量 [AUTO-TRANSLATED:a72494b0]
|
||||
// This variable mainly ensures that the MemThreadInfo variable can be released only after the thread exits
|
||||
static thread_local MemThreadInfoLocal s_thread_mem_info;
|
||||
|
||||
uint64_t getTotalMemUsage() {
|
||||
|
@ -21,110 +21,143 @@ namespace mediakit {
|
||||
|
||||
class ProtocolOption;
|
||||
|
||||
// 加载配置文件,如果配置文件不存在,那么会导出默认配置并生成配置文件
|
||||
// 加载配置文件成功后会触发kBroadcastUpdateConfig广播
|
||||
// 如果指定的文件名(ini_path)为空,那么会加载默认配置文件
|
||||
// 默认配置文件名为 /path/to/your/exe.ini
|
||||
// 加载配置文件成功后返回true,否则返回false
|
||||
// 加载配置文件,如果配置文件不存在,那么会导出默认配置并生成配置文件 [AUTO-TRANSLATED:16d0b898]
|
||||
// Load the configuration file. If the configuration file does not exist, the default configuration will be exported and the configuration file will be generated.
|
||||
// 加载配置文件成功后会触发kBroadcastUpdateConfig广播 [AUTO-TRANSLATED:327e5be2]
|
||||
// After the configuration file is loaded successfully, the kBroadcastUpdateConfig broadcast will be triggered.
|
||||
// 如果指定的文件名(ini_path)为空,那么会加载默认配置文件 [AUTO-TRANSLATED:e241a2b7]
|
||||
// If the specified file name (ini_path) is empty, the default configuration file will be loaded.
|
||||
// 默认配置文件名为 /path/to/your/exe.ini [AUTO-TRANSLATED:2d1acfcb]
|
||||
// The default configuration file name is /path/to/your/exe.ini
|
||||
// 加载配置文件成功后返回true,否则返回false [AUTO-TRANSLATED:cba43e43]
|
||||
// Returns true if the configuration file is loaded successfully, otherwise returns false.
|
||||
bool loadIniConfig(const char *ini_path = nullptr);
|
||||
|
||||
////////////广播名称///////////
|
||||
// //////////广播名称/////////// [AUTO-TRANSLATED:439b2d74]
|
||||
// //////////Broadcast Name///////////
|
||||
namespace Broadcast {
|
||||
|
||||
// 注册或反注册MediaSource事件广播
|
||||
// 注册或反注册MediaSource事件广播 [AUTO-TRANSLATED:ec55c1cf]
|
||||
// Register or unregister MediaSource event broadcast
|
||||
extern const std::string kBroadcastMediaChanged;
|
||||
#define BroadcastMediaChangedArgs const bool &bRegist, MediaSource &sender
|
||||
|
||||
// 录制mp4文件成功后广播
|
||||
// 录制mp4文件成功后广播 [AUTO-TRANSLATED:479ec954]
|
||||
// Broadcast after recording mp4 file successfully
|
||||
extern const std::string kBroadcastRecordMP4;
|
||||
#define BroadcastRecordMP4Args const RecordInfo &info
|
||||
|
||||
// 录制 ts 文件后广播
|
||||
// 录制 ts 文件后广播 [AUTO-TRANSLATED:63a8868c]
|
||||
// Broadcast after recording ts file
|
||||
extern const std::string kBroadcastRecordTs;
|
||||
#define BroadcastRecordTsArgs const RecordInfo &info
|
||||
|
||||
// 收到http api请求广播
|
||||
// 收到http api请求广播 [AUTO-TRANSLATED:c72e7c3f]
|
||||
// Broadcast for receiving http api request
|
||||
extern const std::string kBroadcastHttpRequest;
|
||||
#define BroadcastHttpRequestArgs const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, bool &consumed, SockInfo &sender
|
||||
|
||||
// 在http文件服务器中,收到http访问文件或目录的广播,通过该事件控制访问http目录的权限
|
||||
// 在http文件服务器中,收到http访问文件或目录的广播,通过该事件控制访问http目录的权限 [AUTO-TRANSLATED:2de426b4]
|
||||
// In the http file server, broadcast for receiving http access to files or directories. Control access permissions to the http directory through this event.
|
||||
extern const std::string kBroadcastHttpAccess;
|
||||
#define BroadcastHttpAccessArgs const Parser &parser, const std::string &path, const bool &is_dir, const HttpSession::HttpAccessPathInvoker &invoker, SockInfo &sender
|
||||
|
||||
// 在http文件服务器中,收到http访问文件或目录前的广播,通过该事件可以控制http url到文件路径的映射
|
||||
// 在该事件中通过自行覆盖path参数,可以做到譬如根据虚拟主机或者app选择不同http根目录的目的
|
||||
// 在http文件服务器中,收到http访问文件或目录前的广播,通过该事件可以控制http url到文件路径的映射 [AUTO-TRANSLATED:0294d0c5]
|
||||
// In the http file server, broadcast before receiving http access to files or directories. Control the mapping from http url to file path through this event.
|
||||
// 在该事件中通过自行覆盖path参数,可以做到譬如根据虚拟主机或者app选择不同http根目录的目的 [AUTO-TRANSLATED:1bea3efb]
|
||||
// By overriding the path parameter in this event, you can achieve the purpose of selecting different http root directories based on virtual hosts or apps.
|
||||
extern const std::string kBroadcastHttpBeforeAccess;
|
||||
#define BroadcastHttpBeforeAccessArgs const Parser &parser, std::string &path, SockInfo &sender
|
||||
|
||||
// 该流是否需要认证?是的话调用invoker并传入realm,否则传入空的realm.如果该事件不监听则不认证
|
||||
// 该流是否需要认证?是的话调用invoker并传入realm,否则传入空的realm.如果该事件不监听则不认证 [AUTO-TRANSLATED:5f436d8f]
|
||||
// Does this stream need authentication? If yes, call invoker and pass in realm, otherwise pass in an empty realm. If this event is not listened to, no authentication will be performed.
|
||||
extern const std::string kBroadcastOnGetRtspRealm;
|
||||
#define BroadcastOnGetRtspRealmArgs const MediaInfo &args, const RtspSession::onGetRealm &invoker, SockInfo &sender
|
||||
|
||||
// 请求认证用户密码事件,user_name为用户名,must_no_encrypt如果为true,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败
|
||||
// 获取到密码后请调用invoker并输入对应类型的密码和密码类型,invoker执行时会匹配密码
|
||||
// 请求认证用户密码事件,user_name为用户名,must_no_encrypt如果为true,则必须提供明文密码(因为此时是base64认证方式),否则会导致认证失败 [AUTO-TRANSLATED:22b6dfcc]
|
||||
// Request authentication user password event, user_name is the username, must_no_encrypt if true, then the plaintext password must be provided (because it is base64 authentication method at this time), otherwise it will lead to authentication failure.
|
||||
// 获取到密码后请调用invoker并输入对应类型的密码和密码类型,invoker执行时会匹配密码 [AUTO-TRANSLATED:8c57fd43]
|
||||
// After getting the password, please call invoker and input the corresponding type of password and password type. The invoker will match the password when executing.
|
||||
extern const std::string kBroadcastOnRtspAuth;
|
||||
#define BroadcastOnRtspAuthArgs const MediaInfo &args, const std::string &realm, const std::string &user_name, const bool &must_no_encrypt, const RtspSession::onAuth &invoker, SockInfo &sender
|
||||
|
||||
// 推流鉴权结果回调对象
|
||||
// 如果err为空则代表鉴权成功
|
||||
// 推流鉴权结果回调对象 [AUTO-TRANSLATED:7e508ed1]
|
||||
// Push stream authentication result callback object
|
||||
// 如果err为空则代表鉴权成功 [AUTO-TRANSLATED:d49b0544]
|
||||
// If err is empty, it means authentication is successful.
|
||||
using PublishAuthInvoker = std::function<void(const std::string &err, const ProtocolOption &option)>;
|
||||
|
||||
// 收到rtsp/rtmp推流事件广播,通过该事件控制推流鉴权
|
||||
// 收到rtsp/rtmp推流事件广播,通过该事件控制推流鉴权 [AUTO-TRANSLATED:72417373]
|
||||
// Broadcast for receiving rtsp/rtmp push stream event. Control push stream authentication through this event.
|
||||
extern const std::string kBroadcastMediaPublish;
|
||||
#define BroadcastMediaPublishArgs const MediaOriginType &type, const MediaInfo &args, const Broadcast::PublishAuthInvoker &invoker, SockInfo &sender
|
||||
|
||||
// 播放鉴权结果回调对象
|
||||
// 如果err为空则代表鉴权成功
|
||||
// 播放鉴权结果回调对象 [AUTO-TRANSLATED:c980162b]
|
||||
// Playback authentication result callback object
|
||||
// 如果err为空则代表鉴权成功 [AUTO-TRANSLATED:d49b0544]
|
||||
// If err is empty, it means authentication is successful.
|
||||
using AuthInvoker = std::function<void(const std::string &err)>;
|
||||
|
||||
// 播放rtsp/rtmp/http-flv事件广播,通过该事件控制播放鉴权
|
||||
// 播放rtsp/rtmp/http-flv事件广播,通过该事件控制播放鉴权 [AUTO-TRANSLATED:eddd7014]
|
||||
// Broadcast for playing rtsp/rtmp/http-flv events. Control playback authentication through this event.
|
||||
extern const std::string kBroadcastMediaPlayed;
|
||||
#define BroadcastMediaPlayedArgs const MediaInfo &args, const Broadcast::AuthInvoker &invoker, SockInfo &sender
|
||||
|
||||
// shell登录鉴权
|
||||
// shell登录鉴权 [AUTO-TRANSLATED:26b135d4]
|
||||
// Shell login authentication
|
||||
extern const std::string kBroadcastShellLogin;
|
||||
#define BroadcastShellLoginArgs const std::string &user_name, const std::string &passwd, const Broadcast::AuthInvoker &invoker, SockInfo &sender
|
||||
|
||||
// 停止rtsp/rtmp/http-flv会话后流量汇报事件广播
|
||||
// 停止rtsp/rtmp/http-flv会话后流量汇报事件广播 [AUTO-TRANSLATED:69df61d8]
|
||||
// Broadcast for traffic reporting event after stopping rtsp/rtmp/http-flv session
|
||||
extern const std::string kBroadcastFlowReport;
|
||||
#define BroadcastFlowReportArgs const MediaInfo &args, const uint64_t &totalBytes, const uint64_t &totalDuration, const bool &isPlayer, SockInfo &sender
|
||||
|
||||
// 未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了
|
||||
// 未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了 [AUTO-TRANSLATED:0c00171d]
|
||||
// This event will be broadcast after the stream is not found. Please pull the stream or other methods to generate the stream after listening to this event, so that you can pull the stream on demand.
|
||||
extern const std::string kBroadcastNotFoundStream;
|
||||
#define BroadcastNotFoundStreamArgs const MediaInfo &args, SockInfo &sender, const std::function<void()> &closePlayer
|
||||
|
||||
// 某个流无人消费时触发,目的为了实现无人观看时主动断开拉流等业务逻辑
|
||||
// 某个流无人消费时触发,目的为了实现无人观看时主动断开拉流等业务逻辑 [AUTO-TRANSLATED:3c45f002]
|
||||
// Triggered when a stream is not consumed by anyone. The purpose is to achieve business logic such as actively disconnecting the pull stream when no one is watching.
|
||||
extern const std::string kBroadcastStreamNoneReader;
|
||||
#define BroadcastStreamNoneReaderArgs MediaSource &sender
|
||||
|
||||
// rtp推流被动停止时触发
|
||||
// rtp推流被动停止时触发 [AUTO-TRANSLATED:43881965]
|
||||
// Triggered when rtp push stream is passively stopped.
|
||||
extern const std::string kBroadcastSendRtpStopped;
|
||||
#define BroadcastSendRtpStoppedArgs MultiMediaSourceMuxer &sender, const std::string &ssrc, const SockException &ex
|
||||
|
||||
// 更新配置文件事件广播,执行loadIniConfig函数加载配置文件成功后会触发该广播
|
||||
// 更新配置文件事件广播,执行loadIniConfig函数加载配置文件成功后会触发该广播 [AUTO-TRANSLATED:ad4e167d]
|
||||
// Update configuration file event broadcast. This broadcast will be triggered after the loadIniConfig function loads the configuration file successfully.
|
||||
extern const std::string kBroadcastReloadConfig;
|
||||
#define BroadcastReloadConfigArgs void
|
||||
|
||||
// rtp server 超时
|
||||
// rtp server 超时 [AUTO-TRANSLATED:a65573fd]
|
||||
// Rtp server timeout
|
||||
extern const std::string kBroadcastRtpServerTimeout;
|
||||
#define BroadcastRtpServerTimeoutArgs uint16_t &local_port, const MediaTuple &tuple, int &tcp_mode, bool &re_use_port, uint32_t &ssrc
|
||||
|
||||
// rtc transport sctp 连接状态
|
||||
// rtc transport sctp 连接状态 [AUTO-TRANSLATED:f00284da]
|
||||
// Rtc transport sctp connection status
|
||||
extern const std::string kBroadcastRtcSctpConnecting;
|
||||
extern const std::string kBroadcastRtcSctpConnected;
|
||||
extern const std::string kBroadcastRtcSctpFailed;
|
||||
extern const std::string kBroadcastRtcSctpClosed;
|
||||
#define BroadcastRtcSctpConnectArgs WebRtcTransport& sender
|
||||
|
||||
// rtc transport sctp 发送数据
|
||||
// rtc transport sctp 发送数据 [AUTO-TRANSLATED:258f1ba8]
|
||||
// rtc transport sctp send data
|
||||
extern const std::string kBroadcastRtcSctpSend;
|
||||
#define BroadcastRtcSctpSendArgs WebRtcTransport& sender, const uint8_t *&data, size_t& len
|
||||
|
||||
// rtc transport sctp 接收数据
|
||||
// rtc transport sctp 接收数据 [AUTO-TRANSLATED:ce4cb57e]
|
||||
// rtc transport sctp receive data
|
||||
extern const std::string kBroadcastRtcSctpReceived;
|
||||
#define BroadcastRtcSctpReceivedArgs WebRtcTransport& sender, uint16_t &streamId, uint32_t &ppid, const uint8_t *&msg, size_t &len
|
||||
|
||||
// 观看人数变化广播
|
||||
// 观看人数变化广播 [AUTO-TRANSLATED:5b246b54]
|
||||
// broadcast viewer count changes
|
||||
extern const std::string kBroadcastPlayerCountChanged;
|
||||
#define BroadcastPlayerCountChangedArgs const MediaTuple& args, const int& count
|
||||
|
||||
@ -139,7 +172,8 @@ extern const std::string kBroadcastPlayerCountChanged;
|
||||
InfoL << "reload config:" << key << "=" << arg; \
|
||||
} while (0)
|
||||
|
||||
// 监听某个配置发送变更
|
||||
// 监听某个配置发送变更 [AUTO-TRANSLATED:7f46b5b1]
|
||||
// listen for configuration changes
|
||||
#define LISTEN_RELOAD_KEY(arg, key, ...) \
|
||||
do { \
|
||||
static ::toolkit::onceToken s_token_listen([]() { \
|
||||
@ -168,91 +202,133 @@ extern const std::string kBroadcastPlayerCountChanged;
|
||||
|
||||
} // namespace Broadcast
|
||||
|
||||
////////////通用配置///////////
|
||||
// //////////通用配置/////////// [AUTO-TRANSLATED:b09b9640]
|
||||
// //////////General Configuration///////////
|
||||
namespace General {
|
||||
// 每个流媒体服务器的ID(GUID)
|
||||
// 每个流媒体服务器的ID(GUID) [AUTO-TRANSLATED:c6ac6e56]
|
||||
// ID (GUID) of each media server
|
||||
extern const std::string kMediaServerId;
|
||||
// 流量汇报事件流量阈值,单位KB,默认1MB
|
||||
// 流量汇报事件流量阈值,单位KB,默认1MB [AUTO-TRANSLATED:fd036326]
|
||||
// Traffic reporting event traffic threshold, unit KB, default 1MB
|
||||
extern const std::string kFlowThreshold;
|
||||
// 流无人观看并且超过若干时间后才触发kBroadcastStreamNoneReader事件
|
||||
// 默认连续5秒无人观看然后触发kBroadcastStreamNoneReader事件
|
||||
// 流无人观看并且超过若干时间后才触发kBroadcastStreamNoneReader事件 [AUTO-TRANSLATED:baeea387]
|
||||
// Trigger kBroadcastStreamNoneReader event only after the stream has been unwatched for a certain period of time
|
||||
// 默认连续5秒无人观看然后触发kBroadcastStreamNoneReader事件 [AUTO-TRANSLATED:477bf488]
|
||||
// Default to trigger kBroadcastStreamNoneReader event after 5 seconds of no viewers
|
||||
extern const std::string kStreamNoneReaderDelayMS;
|
||||
// 等待流注册超时时间,收到播放器后请求后,如果未找到相关流,服务器会等待一定时间,
|
||||
// 如果在这个时间内,相关流注册上了,那么服务器会立即响应播放器播放成功,
|
||||
// 否则会最多等待kMaxStreamWaitTimeMS毫秒,然后响应播放器播放失败
|
||||
// 等待流注册超时时间,收到播放器后请求后,如果未找到相关流,服务器会等待一定时间, [AUTO-TRANSLATED:7ccd518d]
|
||||
// Stream registration timeout, after receiving the player's request, if the related stream is not found, the server will wait for a certain period of time,
|
||||
// 如果在这个时间内,相关流注册上了,那么服务器会立即响应播放器播放成功, [AUTO-TRANSLATED:93ef0249]
|
||||
// If the related stream is registered within this time, the server will immediately respond to the player that the playback is successful,
|
||||
// 否则会最多等待kMaxStreamWaitTimeMS毫秒,然后响应播放器播放失败 [AUTO-TRANSLATED:f8c9f19e]
|
||||
// Otherwise, it will wait for a maximum of kMaxStreamWaitTimeMS milliseconds and then respond to the player that the playback failed
|
||||
extern const std::string kMaxStreamWaitTimeMS;
|
||||
// 是否启动虚拟主机
|
||||
// 是否启动虚拟主机 [AUTO-TRANSLATED:e1cea728]
|
||||
// Whether to enable virtual host
|
||||
extern const std::string kEnableVhost;
|
||||
// 拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始,
|
||||
// 如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写)
|
||||
// 拉流代理时如果断流再重连成功是否删除前一次的媒体流数据,如果删除将重新开始, [AUTO-TRANSLATED:d150ffaa]
|
||||
// When pulling stream proxy, whether to delete the previous media stream data if the stream is disconnected and reconnected successfully, if deleted, it will start again,
|
||||
// 如果不删除将会接着上一次的数据继续写(录制hls/mp4时会继续在前一个文件后面写) [AUTO-TRANSLATED:21a5be7e]
|
||||
// If not deleted, it will continue to write from the previous data (when recording hls/mp4, it will continue to write after the previous file)
|
||||
extern const std::string kResetWhenRePlay;
|
||||
// 合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时
|
||||
// 开启后会同时关闭TCP_NODELAY并开启MSG_MORE
|
||||
// 合并写缓存大小(单位毫秒),合并写指服务器缓存一定的数据后才会一次性写入socket,这样能提高性能,但是会提高延时 [AUTO-TRANSLATED:6cc6fcf7]
|
||||
// Merge write cache size (unit milliseconds), merge write refers to the server caching a certain amount of data before writing to the socket at once, which can improve performance but increase latency
|
||||
// 开启后会同时关闭TCP_NODELAY并开启MSG_MORE [AUTO-TRANSLATED:953b82cf]
|
||||
// When enabled, TCP_NODELAY will be closed and MSG_MORE will be enabled at the same time
|
||||
extern const std::string kMergeWriteMS;
|
||||
// 在docker环境下,不能通过英伟达驱动是否存在来判断是否支持硬件转码
|
||||
// 在docker环境下,不能通过英伟达驱动是否存在来判断是否支持硬件转码 [AUTO-TRANSLATED:de678431]
|
||||
// In the docker environment, the existence of the NVIDIA driver cannot be used to determine whether hardware transcoding is supported
|
||||
extern const std::string kCheckNvidiaDev;
|
||||
// 是否开启ffmpeg日志
|
||||
// 是否开启ffmpeg日志 [AUTO-TRANSLATED:038b471e]
|
||||
// Whether to enable ffmpeg log
|
||||
extern const std::string kEnableFFmpegLog;
|
||||
// 最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track
|
||||
// 最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track [AUTO-TRANSLATED:826cd533]
|
||||
// Maximum wait time for uninitialized Track is 10 seconds, after timeout, uninitialized Track will be ignored
|
||||
extern const std::string kWaitTrackReadyMS;
|
||||
//最多等待音频Track收到数据时间,单位毫秒,超时且完全没收到音频数据,忽略音频Track
|
||||
//加快某些带封装的流metadata说明有音频,但是实际上没有的流ready时间(比如很多厂商的GB28181 PS)
|
||||
extern const std::string kWaitAudioTrackDataMS;
|
||||
// 如果直播流只有单Track,最多等待3秒,超时后未收到其他Track的数据,则认为是单Track
|
||||
// 如果协议元数据有声明特定track数,那么无此等待时间
|
||||
// 如果直播流只有单Track,最多等待3秒,超时后未收到其他Track的数据,则认为是单Track [AUTO-TRANSLATED:0e7a364d]
|
||||
// If the live stream has only one Track, wait for a maximum of 3 seconds, if no data from other Tracks is received after timeout, it is considered a single Track
|
||||
// 如果协议元数据有声明特定track数,那么无此等待时间 [AUTO-TRANSLATED:76606846]
|
||||
// If the protocol metadata declares a specific number of tracks, there is no such waiting time
|
||||
extern const std::string kWaitAddTrackMS;
|
||||
// 如果track未就绪,我们先缓存帧数据,但是有最大个数限制(100帧时大约4秒),防止内存溢出
|
||||
// 如果track未就绪,我们先缓存帧数据,但是有最大个数限制(100帧时大约4秒),防止内存溢出 [AUTO-TRANSLATED:c520054f]
|
||||
// If the track is not ready, we will cache the frame data first, but there is a maximum number limit (100 frames is about 4 seconds) to prevent memory overflow
|
||||
extern const std::string kUnreadyFrameCache;
|
||||
// 是否启用观看人数变化事件广播,置1则启用,置0则关闭
|
||||
// 是否启用观看人数变化事件广播,置1则启用,置0则关闭 [AUTO-TRANSLATED:3b7f0748]
|
||||
// Whether to enable viewer count change event broadcast, set to 1 to enable, set to 0 to disable
|
||||
extern const std::string kBroadcastPlayerCountChanged;
|
||||
// 绑定的本地网卡ip
|
||||
// 绑定的本地网卡ip [AUTO-TRANSLATED:daa90832]
|
||||
// Bound local network card ip
|
||||
extern const std::string kListenIP;
|
||||
} // namespace General
|
||||
|
||||
namespace Protocol {
|
||||
static constexpr char kFieldName[] = "protocol.";
|
||||
//时间戳修复这一路流标志位
|
||||
// 时间戳修复这一路流标志位 [AUTO-TRANSLATED:cc208f41]
|
||||
// Timestamp repair flag for this stream
|
||||
extern const std::string kModifyStamp;
|
||||
//转协议是否开启音频
|
||||
// 转协议是否开启音频 [AUTO-TRANSLATED:220dddfa]
|
||||
// Whether to enable audio for protocol conversion
|
||||
extern const std::string kEnableAudio;
|
||||
//添加静音音频,在关闭音频时,此开关无效
|
||||
// 添加静音音频,在关闭音频时,此开关无效 [AUTO-TRANSLATED:47c0ec8e]
|
||||
// Add silent audio, this switch is invalid when audio is closed
|
||||
extern const std::string kAddMuteAudio;
|
||||
// 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close)
|
||||
// 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调,
|
||||
// 而是将直接关闭流
|
||||
// 无人观看时,是否直接关闭(而不是通过on_none_reader hook返回close) [AUTO-TRANSLATED:dba7ab70]
|
||||
// When there are no viewers, whether to close directly (instead of returning close through the on_none_reader hook)
|
||||
// 此配置置1时,此流如果无人观看,将不触发on_none_reader hook回调, [AUTO-TRANSLATED:a5ead314]
|
||||
// When this configuration is set to 1, if this stream has no viewers, it will not trigger the on_none_reader hook callback,
|
||||
// 而是将直接关闭流 [AUTO-TRANSLATED:06887d49]
|
||||
// Instead, it will directly close the stream
|
||||
extern const std::string kAutoClose;
|
||||
//断连续推延时,单位毫秒,默认采用配置文件
|
||||
// 断连续推延时,单位毫秒,默认采用配置文件 [AUTO-TRANSLATED:7a15b12f]
|
||||
// When the continuous delay is interrupted, the unit is milliseconds, and the configuration file is used by default
|
||||
extern const std::string kContinuePushMS;
|
||||
// 平滑发送定时器间隔,单位毫秒,置0则关闭;开启后影响cpu性能同时增加内存
|
||||
// 该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题
|
||||
// 平滑发送定时器间隔,单位毫秒,置0则关闭;开启后影响cpu性能同时增加内存 [AUTO-TRANSLATED:ad4e306a]
|
||||
// Smooth sending timer interval, unit is milliseconds, set to 0 to close; enabling it will affect CPU performance and increase memory
|
||||
// 该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题 [AUTO-TRANSLATED:0f2b1657]
|
||||
// Enabling this configuration can solve some problems where the stream is not sent smoothly, resulting in ZLMediaKit forwarding not being smooth
|
||||
extern const std::string kPacedSenderMS;
|
||||
|
||||
//是否开启转换为hls(mpegts)
|
||||
// 是否开启转换为hls(mpegts) [AUTO-TRANSLATED:bfc1167a]
|
||||
// Whether to enable conversion to HLS (MPEGTS)
|
||||
extern const std::string kEnableHls;
|
||||
//是否开启转换为hls(fmp4)
|
||||
// 是否开启转换为hls(fmp4) [AUTO-TRANSLATED:20548673]
|
||||
// Whether to enable conversion to HLS (FMP4)
|
||||
extern const std::string kEnableHlsFmp4;
|
||||
//是否开启MP4录制
|
||||
// 是否开启MP4录制 [AUTO-TRANSLATED:0157b014]
|
||||
// Whether to enable MP4 recording
|
||||
extern const std::string kEnableMP4;
|
||||
//是否开启转换为rtsp/webrtc
|
||||
// 是否开启转换为rtsp/webrtc [AUTO-TRANSLATED:0711cb18]
|
||||
// Whether to enable conversion to RTSP/WebRTC
|
||||
extern const std::string kEnableRtsp;
|
||||
//是否开启转换为rtmp/flv
|
||||
// 是否开启转换为rtmp/flv [AUTO-TRANSLATED:d4774119]
|
||||
// Whether to enable conversion to RTMP/FLV
|
||||
extern const std::string kEnableRtmp;
|
||||
//是否开启转换为http-ts/ws-ts
|
||||
// 是否开启转换为http-ts/ws-ts [AUTO-TRANSLATED:51acc798]
|
||||
// Whether to enable conversion to HTTP-TS/WS-TS
|
||||
extern const std::string kEnableTS;
|
||||
//是否开启转换为http-fmp4/ws-fmp4
|
||||
// 是否开启转换为http-fmp4/ws-fmp4 [AUTO-TRANSLATED:8c96e1e4]
|
||||
// Whether to enable conversion to HTTP-FMP4/WS-FMP4
|
||||
extern const std::string kEnableFMP4;
|
||||
|
||||
//是否将mp4录制当做观看者
|
||||
// 是否将mp4录制当做观看者 [AUTO-TRANSLATED:ba351230]
|
||||
// Whether to treat MP4 recording as a viewer
|
||||
extern const std::string kMP4AsPlayer;
|
||||
//mp4切片大小,单位秒
|
||||
// mp4切片大小,单位秒 [AUTO-TRANSLATED:c3fb8ec1]
|
||||
// MP4 fragment size, unit is seconds
|
||||
extern const std::string kMP4MaxSecond;
|
||||
//mp4录制保存路径
|
||||
// mp4录制保存路径 [AUTO-TRANSLATED:6d860f27]
|
||||
// MP4 recording save path
|
||||
extern const std::string kMP4SavePath;
|
||||
|
||||
//hls录制保存路径
|
||||
// hls录制保存路径 [AUTO-TRANSLATED:cfa90719]
|
||||
// HLS recording save path
|
||||
extern const std::string kHlsSavePath;
|
||||
|
||||
// 按需转协议的开关
|
||||
// 按需转协议的开关 [AUTO-TRANSLATED:9f350899]
|
||||
// On-demand protocol conversion switch
|
||||
extern const std::string kHlsDemand;
|
||||
extern const std::string kRtspDemand;
|
||||
extern const std::string kRtmpDemand;
|
||||
@ -260,159 +336,230 @@ extern const std::string kTSDemand;
|
||||
extern const std::string kFMP4Demand;
|
||||
} // !Protocol
|
||||
|
||||
////////////HTTP配置///////////
|
||||
// //////////HTTP配置/////////// [AUTO-TRANSLATED:a281d694]
|
||||
// //////////HTTP configuration///////////
|
||||
namespace Http {
|
||||
// http 文件发送缓存大小
|
||||
// http 文件发送缓存大小 [AUTO-TRANSLATED:51fb08c0]
|
||||
// HTTP file sending cache size
|
||||
extern const std::string kSendBufSize;
|
||||
// http 最大请求字节数
|
||||
// http 最大请求字节数 [AUTO-TRANSLATED:8239eb9c]
|
||||
// HTTP maximum request byte size
|
||||
extern const std::string kMaxReqSize;
|
||||
// http keep-alive秒数
|
||||
// http keep-alive秒数 [AUTO-TRANSLATED:d4930c66]
|
||||
// HTTP keep-alive seconds
|
||||
extern const std::string kKeepAliveSecond;
|
||||
// http 字符编码
|
||||
// http 字符编码 [AUTO-TRANSLATED:f7e55c83]
|
||||
// HTTP character encoding
|
||||
extern const std::string kCharSet;
|
||||
// http 服务器根目录
|
||||
// http 服务器根目录 [AUTO-TRANSLATED:f8f55daf]
|
||||
// HTTP server root directory
|
||||
extern const std::string kRootPath;
|
||||
// http 服务器虚拟目录 虚拟目录名和文件路径使用","隔开,多个配置路径间用";"隔开,例如 path_d,d:/record;path_e,e:/record
|
||||
// http 服务器虚拟目录 虚拟目录名和文件路径使用","隔开,多个配置路径间用";"隔开,例如 path_d,d:/record;path_e,e:/record [AUTO-TRANSLATED:fa4ee929]
|
||||
// HTTP server virtual directory. Virtual directory name and file path are separated by ",", and multiple configuration paths are separated by ";", for example, path_d,d:/record;path_e,e:/record
|
||||
extern const std::string kVirtualPath;
|
||||
// http 404错误提示内容
|
||||
// http 404错误提示内容 [AUTO-TRANSLATED:91adb026]
|
||||
// HTTP 404 error prompt content
|
||||
extern const std::string kNotFound;
|
||||
// 是否显示文件夹菜单
|
||||
// 是否显示文件夹菜单 [AUTO-TRANSLATED:77301b85]
|
||||
// Whether to display the folder menu
|
||||
extern const std::string kDirMenu;
|
||||
// 禁止缓存文件的后缀
|
||||
// 禁止缓存文件的后缀 [AUTO-TRANSLATED:92bcb7f7]
|
||||
// Forbidden cache file suffixes
|
||||
extern const std::string kForbidCacheSuffix;
|
||||
// 可以把http代理前真实客户端ip放在http头中:https://github.com/ZLMediaKit/ZLMediaKit/issues/1388
|
||||
// 可以把http代理前真实客户端ip放在http头中:https://github.com/ZLMediaKit/ZLMediaKit/issues/1388 [AUTO-TRANSLATED:afcd9556]
|
||||
// You can put the real client IP address before the HTTP proxy in the HTTP header: https://github.com/ZLMediaKit/ZLMediaKit/issues/1388
|
||||
extern const std::string kForwardedIpHeader;
|
||||
// 是否允许所有跨域请求
|
||||
// 是否允许所有跨域请求 [AUTO-TRANSLATED:2551c096]
|
||||
// Whether to allow all cross-domain requests
|
||||
extern const std::string kAllowCrossDomains;
|
||||
// 允许访问http api和http文件索引的ip地址范围白名单,置空情况下不做限制
|
||||
// 允许访问http api和http文件索引的ip地址范围白名单,置空情况下不做限制 [AUTO-TRANSLATED:ab939863]
|
||||
// Whitelist of IP address ranges allowed to access HTTP API and HTTP file index. No restrictions are imposed when empty
|
||||
extern const std::string kAllowIPRange;
|
||||
} // namespace Http
|
||||
|
||||
////////////SHELL配置///////////
|
||||
// //////////SHELL配置/////////// [AUTO-TRANSLATED:f023ec45]
|
||||
// //////////SHELL configuration///////////
|
||||
namespace Shell {
|
||||
extern const std::string kMaxReqSize;
|
||||
} // namespace Shell
|
||||
|
||||
////////////RTSP服务器配置///////////
|
||||
// //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981]
|
||||
// //////////RTSP Server Configuration///////////
|
||||
namespace Rtsp {
|
||||
// 是否优先base64方式认证?默认Md5方式认证
|
||||
// 是否优先base64方式认证?默认Md5方式认证 [AUTO-TRANSLATED:0ea332b5]
|
||||
// Is base64 authentication prioritized? Default is Md5 authentication
|
||||
extern const std::string kAuthBasic;
|
||||
// 握手超时时间,默认15秒
|
||||
// 握手超时时间,默认15秒 [AUTO-TRANSLATED:6f69a65b]
|
||||
// Handshake timeout, default 15 seconds
|
||||
extern const std::string kHandshakeSecond;
|
||||
// 维持链接超时时间,默认15秒
|
||||
// 维持链接超时时间,默认15秒 [AUTO-TRANSLATED:b6339c90]
|
||||
// Keep-alive timeout, default 15 seconds
|
||||
extern const std::string kKeepAliveSecond;
|
||||
|
||||
// rtsp拉流代理是否直接代理
|
||||
// 直接代理后支持任意编码格式,但是会导致GOP缓存无法定位到I帧,可能会导致开播花屏
|
||||
// 并且如果是tcp方式拉流,如果rtp大于mtu会导致无法使用udp方式代理
|
||||
// 假定您的拉流源地址不是264或265或AAC,那么你可以使用直接代理的方式来支持rtsp代理
|
||||
// 默认开启rtsp直接代理,rtmp由于没有这些问题,是强制开启直接代理的
|
||||
// rtsp拉流代理是否直接代理 [AUTO-TRANSLATED:9cd82709]
|
||||
// Whether RTSP pull stream proxy is direct proxy
|
||||
// 直接代理后支持任意编码格式,但是会导致GOP缓存无法定位到I帧,可能会导致开播花屏 [AUTO-TRANSLATED:36525a92]
|
||||
// Direct proxy supports any encoding format, but it will cause GOP cache unable to locate I-frame, which may lead to screen flickering
|
||||
// 并且如果是tcp方式拉流,如果rtp大于mtu会导致无法使用udp方式代理 [AUTO-TRANSLATED:a1ab467e]
|
||||
// And if it is TCP pull stream, if RTP is larger than MTU, it will not be able to use UDP proxy
|
||||
// 假定您的拉流源地址不是264或265或AAC,那么你可以使用直接代理的方式来支持rtsp代理 [AUTO-TRANSLATED:9efaedcd]
|
||||
// Assuming your pull stream source address is not 264 or 265 or AAC, then you can use direct proxy to support RTSP proxy
|
||||
// 默认开启rtsp直接代理,rtmp由于没有这些问题,是强制开启直接代理的 [AUTO-TRANSLATED:0e55d051]
|
||||
// Default to enable RTSP direct proxy, RTMP does not have these problems, it is forced to enable direct proxy
|
||||
extern const std::string kDirectProxy;
|
||||
|
||||
// rtsp 转发是否使用低延迟模式,当开启时,不会缓存rtp包,来提高并发,可以降低一帧的延迟
|
||||
// rtsp 转发是否使用低延迟模式,当开启时,不会缓存rtp包,来提高并发,可以降低一帧的延迟 [AUTO-TRANSLATED:f6fe8c6c]
|
||||
// Whether RTSP forwarding uses low latency mode, when enabled, it will not cache RTP packets to improve concurrency and reduce one frame delay
|
||||
extern const std::string kLowLatency;
|
||||
|
||||
//强制协商rtp传输方式 (0:TCP,1:UDP,2:MULTICAST,-1:不限制)
|
||||
//当客户端发起RTSP SETUP的时候如果传输类型和此配置不一致则返回461 Unsupport Transport
|
||||
//迫使客户端重新SETUP并切换到对应协议。目前支持FFMPEG和VLC
|
||||
// 强制协商rtp传输方式 (0:TCP,1:UDP,2:MULTICAST,-1:不限制) [AUTO-TRANSLATED:38574ed5]
|
||||
// Force negotiation of RTP transport method (0: TCP, 1: UDP, 2: MULTICAST, -1: no restriction)
|
||||
// 当客户端发起RTSP SETUP的时候如果传输类型和此配置不一致则返回461 Unsupport Transport [AUTO-TRANSLATED:b0fd0336]
|
||||
// When the client initiates RTSP SETUP, if the transport type is inconsistent with this configuration, it will return 461 Unsupport Transport
|
||||
// 迫使客户端重新SETUP并切换到对应协议。目前支持FFMPEG和VLC [AUTO-TRANSLATED:45f9cddb]
|
||||
// Force the client to re-SETUP and switch to the corresponding protocol. Currently supports FFMPEG and VLC
|
||||
extern const std::string kRtpTransportType;
|
||||
} // namespace Rtsp
|
||||
|
||||
////////////RTMP服务器配置///////////
|
||||
// //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f]
|
||||
// //////////RTMP Server Configuration///////////
|
||||
namespace Rtmp {
|
||||
// 握手超时时间,默认15秒
|
||||
// 握手超时时间,默认15秒 [AUTO-TRANSLATED:6f69a65b]
|
||||
// Handshake timeout, default 15 seconds
|
||||
extern const std::string kHandshakeSecond;
|
||||
// 维持链接超时时间,默认15秒
|
||||
// 维持链接超时时间,默认15秒 [AUTO-TRANSLATED:b6339c90]
|
||||
// Keep-alive timeout, default 15 seconds
|
||||
extern const std::string kKeepAliveSecond;
|
||||
// 是否直接代理
|
||||
// 是否直接代理 [AUTO-TRANSLATED:25268b70]
|
||||
// Whether direct proxy
|
||||
extern const std::string kDirectProxy;
|
||||
// h265-rtmp是否采用增强型(或者国内扩展)
|
||||
// h265-rtmp是否采用增强型(或者国内扩展) [AUTO-TRANSLATED:4a52d042]
|
||||
// Whether h265-rtmp uses enhanced (or domestic extension)
|
||||
extern const std::string kEnhanced;
|
||||
} // namespace Rtmp
|
||||
|
||||
////////////RTP配置///////////
|
||||
// //////////RTP配置/////////// [AUTO-TRANSLATED:23cbcb86]
|
||||
// //////////RTP Configuration///////////
|
||||
namespace Rtp {
|
||||
// RTP打包最大MTU,公网情况下更小
|
||||
// RTP打包最大MTU,公网情况下更小 [AUTO-TRANSLATED:869f5c4b]
|
||||
// Maximum RTP packet MTU, smaller in public network
|
||||
extern const std::string kVideoMtuSize;
|
||||
// RTP打包最大MTU,公网情况下更小
|
||||
// RTP打包最大MTU,公网情况下更小 [AUTO-TRANSLATED:869f5c4b]
|
||||
// Maximum RTP packet MTU, smaller in public network
|
||||
extern const std::string kAudioMtuSize;
|
||||
// rtp包最大长度限制, 单位KB
|
||||
// rtp包最大长度限制, 单位KB [AUTO-TRANSLATED:1da42584]
|
||||
// Maximum RTP packet length limit, unit KB
|
||||
extern const std::string kRtpMaxSize;
|
||||
// rtp 打包时,低延迟开关,默认关闭(为0),h264存在一帧多个slice(NAL)的情况,在这种情况下,如果开启可能会导致画面花屏
|
||||
// rtp 打包时,低延迟开关,默认关闭(为0),h264存在一帧多个slice(NAL)的情况,在这种情况下,如果开启可能会导致画面花屏 [AUTO-TRANSLATED:4cf0cb8d]
|
||||
// When RTP is packaged, low latency switch, default off (0), H264 has multiple slices (NAL) in one frame, in this case, if enabled, it may cause screen flickering
|
||||
extern const std::string kLowLatency;
|
||||
//H264 rtp打包模式是否采用stap-a模式(为了在老版本浏览器上兼容webrtc)还是采用Single NAL unit packet per H.264 模式
|
||||
// H264 rtp打包模式是否采用stap-a模式(为了在老版本浏览器上兼容webrtc)还是采用Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:30632378]
|
||||
// Whether H264 RTP packaging mode uses stap-a mode (for compatibility with webrtc on older browsers) or Single NAL unit packet per H.264 mode
|
||||
extern const std::string kH264StapA;
|
||||
} // namespace Rtp
|
||||
|
||||
////////////组播配置///////////
|
||||
// //////////组播配置/////////// [AUTO-TRANSLATED:dc39b9d6]
|
||||
// //////////Multicast Configuration///////////
|
||||
namespace MultiCast {
|
||||
// 组播分配起始地址
|
||||
// 组播分配起始地址 [AUTO-TRANSLATED:069db91d]
|
||||
// Multicast allocation start address
|
||||
extern const std::string kAddrMin;
|
||||
// 组播分配截止地址
|
||||
// 组播分配截止地址 [AUTO-TRANSLATED:6d3fc54c]
|
||||
// Multicast allocation end address
|
||||
extern const std::string kAddrMax;
|
||||
// 组播TTL
|
||||
// 组播TTL [AUTO-TRANSLATED:c7c5339c]
|
||||
// Multicast TTL
|
||||
extern const std::string kUdpTTL;
|
||||
} // namespace MultiCast
|
||||
|
||||
////////////录像配置///////////
|
||||
// //////////录像配置/////////// [AUTO-TRANSLATED:19de3e96]
|
||||
// //////////Recording Configuration///////////
|
||||
namespace Record {
|
||||
// 查看录像的应用名称
|
||||
// 查看录像的应用名称 [AUTO-TRANSLATED:a71b5daf]
|
||||
// Application name for viewing recordings
|
||||
extern const std::string kAppName;
|
||||
// 每次流化MP4文件的时长,单位毫秒
|
||||
// 每次流化MP4文件的时长,单位毫秒 [AUTO-TRANSLATED:0add878d]
|
||||
// Duration of each MP4 file streaming, in milliseconds
|
||||
extern const std::string kSampleMS;
|
||||
// mp4文件写缓存大小
|
||||
// mp4文件写缓存大小 [AUTO-TRANSLATED:9904413d]
|
||||
// MP4 file write cache size
|
||||
extern const std::string kFileBufSize;
|
||||
// mp4录制完成后是否进行二次关键帧索引写入头部
|
||||
// mp4录制完成后是否进行二次关键帧索引写入头部 [AUTO-TRANSLATED:53cfdcb5]
|
||||
// Whether to perform secondary keyframe index writing to the header after MP4 recording is completed
|
||||
extern const std::string kFastStart;
|
||||
// mp4文件是否重头循环读取
|
||||
// mp4文件是否重头循环读取 [AUTO-TRANSLATED:69ac72de]
|
||||
// Whether to loop read the MP4 file from the beginning
|
||||
extern const std::string kFileRepeat;
|
||||
// mp4录制文件是否采用fmp4格式
|
||||
// mp4录制文件是否采用fmp4格式 [AUTO-TRANSLATED:12559ae0]
|
||||
// Whether to use fmp4 format for MP4 recording files
|
||||
extern const std::string kEnableFmp4;
|
||||
} // namespace Record
|
||||
|
||||
////////////HLS相关配置///////////
|
||||
// //////////HLS相关配置/////////// [AUTO-TRANSLATED:873cc84c]
|
||||
// //////////HLS related configuration///////////
|
||||
namespace Hls {
|
||||
// HLS切片时长,单位秒
|
||||
// HLS切片时长,单位秒 [AUTO-TRANSLATED:ed6a4219]
|
||||
// HLS slice duration, in seconds
|
||||
extern const std::string kSegmentDuration;
|
||||
// m3u8文件中HLS切片个数,如果设置为0,则不删除切片,而是保存为点播
|
||||
// m3u8文件中HLS切片个数,如果设置为0,则不删除切片,而是保存为点播 [AUTO-TRANSLATED:92388a5d]
|
||||
// Number of HLS slices in the m3u8 file. If set to 0, the slices will not be deleted and will be saved as on-demand
|
||||
extern const std::string kSegmentNum;
|
||||
// 如果设置为0,则不保留切片,设置为1则一直保留切片
|
||||
// 如果设置为0,则不保留切片,设置为1则一直保留切片 [AUTO-TRANSLATED:0933fd7b]
|
||||
// If set to 0, the slices will not be retained, if set to 1, the slices will be retained all the time
|
||||
extern const std::string kSegmentKeep;
|
||||
// HLS切片延迟个数,大于0将生成hls_delay.m3u8文件,0则不生成
|
||||
// HLS切片延迟个数,大于0将生成hls_delay.m3u8文件,0则不生成 [AUTO-TRANSLATED:b1751b00]
|
||||
// Number of HLS slice delays. Greater than 0 will generate hls_delay.m3u8 file, 0 will not generate
|
||||
extern const std::string kSegmentDelay;
|
||||
// HLS切片从m3u8文件中移除后,继续保留在磁盘上的个数
|
||||
// HLS切片从m3u8文件中移除后,继续保留在磁盘上的个数 [AUTO-TRANSLATED:b7a23e1a]
|
||||
// Number of HLS slices that continue to be retained on disk after being removed from the m3u8 file
|
||||
extern const std::string kSegmentRetain;
|
||||
// HLS文件写缓存大小
|
||||
// HLS文件写缓存大小 [AUTO-TRANSLATED:81832c8b]
|
||||
// HLS file write cache size
|
||||
extern const std::string kFileBufSize;
|
||||
// 是否广播 ts 切片完成通知
|
||||
// 是否广播 ts 切片完成通知 [AUTO-TRANSLATED:a53644a2]
|
||||
// Whether to broadcast ts slice completion notification
|
||||
extern const std::string kBroadcastRecordTs;
|
||||
// hls直播文件删除延时,单位秒
|
||||
// hls直播文件删除延时,单位秒 [AUTO-TRANSLATED:5643cab7]
|
||||
// HLS live file deletion delay, in seconds
|
||||
extern const std::string kDeleteDelaySec;
|
||||
// 如果设置为1,则第一个切片长度强制设置为1个GOP
|
||||
// 如果设置为1,则第一个切片长度强制设置为1个GOP [AUTO-TRANSLATED:fbbb651d]
|
||||
// If set to 1, the length of the first slice is forced to be 1 GOP
|
||||
extern const std::string kFastRegister;
|
||||
} // namespace Hls
|
||||
|
||||
////////////Rtp代理相关配置///////////
|
||||
// //////////Rtp代理相关配置/////////// [AUTO-TRANSLATED:7b285587]
|
||||
// //////////Rtp proxy related configuration///////////
|
||||
namespace RtpProxy {
|
||||
// rtp调试数据保存目录,置空则不生成
|
||||
// rtp调试数据保存目录,置空则不生成 [AUTO-TRANSLATED:aa004af0]
|
||||
// Rtp debug data save directory, empty if not generated
|
||||
extern const std::string kDumpDir;
|
||||
// rtp接收超时时间
|
||||
// rtp接收超时时间 [AUTO-TRANSLATED:9e918489]
|
||||
// Rtp receive timeout
|
||||
extern const std::string kTimeoutSec;
|
||||
// 随机端口范围,最少确保36个端口
|
||||
// 该范围同时限制rtsp服务器udp端口范围
|
||||
// 随机端口范围,最少确保36个端口 [AUTO-TRANSLATED:2f2b6b17]
|
||||
// Random port range, at least 36 ports are guaranteed
|
||||
// 该范围同时限制rtsp服务器udp端口范围 [AUTO-TRANSLATED:1ff8fd75]
|
||||
// This range also limits the rtsp server udp port range
|
||||
extern const std::string kPortRange;
|
||||
// rtp server h264的pt
|
||||
// rtp server h264的pt [AUTO-TRANSLATED:b8cf877b]
|
||||
// Rtp server h264 pt
|
||||
extern const std::string kH264PT;
|
||||
// rtp server h265的pt
|
||||
// rtp server h265的pt [AUTO-TRANSLATED:2bdb1dfb]
|
||||
// Rtp server h265 pt
|
||||
extern const std::string kH265PT;
|
||||
// rtp server ps 的pt
|
||||
// rtp server ps 的pt [AUTO-TRANSLATED:6feaf5f9]
|
||||
// Rtp server ps pt
|
||||
extern const std::string kPSPT;
|
||||
// rtp server opus 的pt
|
||||
// rtp server opus 的pt [AUTO-TRANSLATED:9f91f85a]
|
||||
// Rtp server opus pt
|
||||
extern const std::string kOpusPT;
|
||||
// RtpSender相关功能是否提前开启gop缓存优化级联秒开体验,默认开启
|
||||
// RtpSender相关功能是否提前开启gop缓存优化级联秒开体验,默认开启 [AUTO-TRANSLATED:40c37c77]
|
||||
// Whether to enable gop cache optimization cascade second-open experience for RtpSender related functions, enabled by default
|
||||
extern const std::string kGopCache;
|
||||
//国标发送g711 rtp 打包时,每个包的语音时长是多少,默认是100 ms,范围为20~180ms (gb28181-2016,c.2.4规定),
|
||||
//最好为20 的倍数,程序自动向20的倍数取整
|
||||
// 国标发送g711 rtp 打包时,每个包的语音时长是多少,默认是100 ms,范围为20~180ms (gb28181-2016,c.2.4规定), [AUTO-TRANSLATED:3b3916a3]
|
||||
// When sending g711 rtp packets in national standard, what is the duration of each packet, the default is 100 ms, the range is 20~180ms (gb28181-2016, c.2.4),
|
||||
// 最好为20 的倍数,程序自动向20的倍数取整 [AUTO-TRANSLATED:7bc6e0ec]
|
||||
// It is best to be a multiple of 20, the program automatically rounds to the nearest multiple of 20
|
||||
extern const std::string kRtpG711DurMs;
|
||||
// udp recv socket buffer size
|
||||
extern const std::string kUdpRecvSocketBuffer;
|
||||
@ -422,38 +569,60 @@ extern const std::string kUdpRecvSocketBuffer;
|
||||
* rtsp/rtmp播放器、推流器相关设置名,
|
||||
* 这些设置项都不是配置文件用
|
||||
* 只用于设置某个播放器或推流器实例用
|
||||
* Rtsp/rtmp player, pusher related settings name,
|
||||
* These settings are not used in the configuration file
|
||||
* Only used to set a specific player or pusher instance
|
||||
|
||||
* [AUTO-TRANSLATED:59086953]
|
||||
*/
|
||||
namespace Client {
|
||||
// 指定网卡ip
|
||||
// 指定网卡ip [AUTO-TRANSLATED:679fdccb]
|
||||
// Specify network card ip
|
||||
extern const std::string kNetAdapter;
|
||||
// 设置rtp传输类型,可选项有0(tcp,默认)、1(udp)、2(组播)
|
||||
// 设置方法:player[PlayerBase::kRtpType] = 0/1/2;
|
||||
// 设置rtp传输类型,可选项有0(tcp,默认)、1(udp)、2(组播) [AUTO-TRANSLATED:bf73f779]
|
||||
// Set rtp transport type, options are 0 (tcp, default), 1 (udp), 2 (multicast)
|
||||
// 设置方法:player[PlayerBase::kRtpType] = 0/1/2; [AUTO-TRANSLATED:30eb2936]
|
||||
// Set method: player[PlayerBase::kRtpType] = 0/1/2;
|
||||
extern const std::string kRtpType;
|
||||
// rtsp播放器发送信令心跳还是rtcp心跳,可选项有0(同时发)、1(rtcp心跳)、2(信令心跳)
|
||||
// 设置方法:player[PlayerBase::kRtspBeatType] = 0/1/2;
|
||||
// rtsp播放器发送信令心跳还是rtcp心跳,可选项有0(同时发)、1(rtcp心跳)、2(信令心跳) [AUTO-TRANSLATED:56d9ac7c]
|
||||
// Whether the RTSP player sends signaling heartbeat or RTCP heartbeat, options are 0 (both), 1 (RTCP heartbeat), 2 (signaling heartbeat)
|
||||
// 设置方法:player[PlayerBase::kRtspBeatType] = 0/1/2; [AUTO-TRANSLATED:ccc0726b]
|
||||
// Set method: player[PlayerBase::kRtspBeatType] = 0/1/2;
|
||||
extern const std::string kRtspBeatType;
|
||||
// rtsp认证用户名
|
||||
// rtsp认证用户名 [AUTO-TRANSLATED:5ab80e57]
|
||||
// RTSP authentication username
|
||||
extern const std::string kRtspUser;
|
||||
// rtsp认证用用户密码,可以是明文也可以是md5,md5密码生成方式 md5(username:realm:password)
|
||||
// rtsp认证用用户密码,可以是明文也可以是md5,md5密码生成方式 md5(username:realm:password) [AUTO-TRANSLATED:1228f997]
|
||||
// RTSP authentication user password, can be plain text or MD5, MD5 password generation method md5(username:realm:password)
|
||||
extern const std::string kRtspPwd;
|
||||
// rtsp认证用用户密码是否为md5类型
|
||||
// rtsp认证用用户密码是否为md5类型 [AUTO-TRANSLATED:208696d1]
|
||||
// Whether the RTSP authentication user password is MD5 type
|
||||
extern const std::string kRtspPwdIsMD5;
|
||||
// 握手超时时间,默认10,000 毫秒
|
||||
// 握手超时时间,默认10,000 毫秒 [AUTO-TRANSLATED:44b3f73f]
|
||||
// Handshake timeout, default 10,000 milliseconds
|
||||
extern const std::string kTimeoutMS;
|
||||
// rtp/rtmp包接收超时时间,默认5000秒
|
||||
// rtp/rtmp包接收超时时间,默认5000秒 [AUTO-TRANSLATED:e450d4cc]
|
||||
// RTP/RTMP packet receive timeout, default 5000 seconds
|
||||
extern const std::string kMediaTimeoutMS;
|
||||
// rtsp/rtmp心跳时间,默认5000毫秒
|
||||
// rtsp/rtmp心跳时间,默认5000毫秒 [AUTO-TRANSLATED:4d64f27f]
|
||||
// RTSP/RTMP heartbeat time, default 5000 milliseconds
|
||||
extern const std::string kBeatIntervalMS;
|
||||
// 是否为性能测试模式,性能测试模式开启后不会解析rtp或rtmp包
|
||||
// 是否为性能测试模式,性能测试模式开启后不会解析rtp或rtmp包 [AUTO-TRANSLATED:be9a797d]
|
||||
// Whether it is performance test mode, performance test mode will not parse RTP or RTMP packets after being turned on
|
||||
extern const std::string kBenchmarkMode;
|
||||
// 播放器在触发播放成功事件时,是否等待所有track ready时再回调
|
||||
// 播放器在触发播放成功事件时,是否等待所有track ready时再回调 [AUTO-TRANSLATED:73523e6d]
|
||||
// Whether the player waits for all tracks to be ready before calling back when triggering the playback success event
|
||||
extern const std::string kWaitTrackReady;
|
||||
// rtsp播放指定track,可选项有0(不指定,默认)、1(视频)、2(音频)
|
||||
// 设置方法:player[Client::kPlayTrack] = 0/1/2;
|
||||
// rtsp播放指定track,可选项有0(不指定,默认)、1(视频)、2(音频) [AUTO-TRANSLATED:e4f481f9]
|
||||
// RTSP playback specified track, options are 0 (not specified, default), 1 (video), 2 (audio)
|
||||
// 设置方法:player[Client::kPlayTrack] = 0/1/2; [AUTO-TRANSLATED:0a2705c8]
|
||||
// Set method: player[Client::kPlayTrack] = 0/1/2;
|
||||
extern const std::string kPlayTrack;
|
||||
//设置代理url,目前只支持http协议
|
||||
// 设置代理url,目前只支持http协议 [AUTO-TRANSLATED:c84918cc]
|
||||
// Set proxy url, currently only supports http protocol
|
||||
extern const std::string kProxyUrl;
|
||||
//设置开始rtsp倍速播放
|
||||
// 设置开始rtsp倍速播放 [AUTO-TRANSLATED:5db03cad]
|
||||
// Set the start RTSP playback speed
|
||||
extern const std::string kRtspSpeed;
|
||||
} // namespace Client
|
||||
} // namespace mediakit
|
||||
|
@ -22,6 +22,12 @@ namespace mediakit {
|
||||
* 本项目采用类MIT协议,用户在履行MIT协议义务的同时,应当同时遵循保留ZLMediaKit软件版权信息的义务。
|
||||
* 用户不得去除ZLMediaKit提供的各种服务中包括但不限于 "title"、"Server"、"User-Agent" 等字段中 "ZLMediaKit" 的信息。
|
||||
* 否则本项目主要权利人(项目发起人、主要作者)保留声索起诉的权利。
|
||||
* This project adopts a class MIT license. Users, while fulfilling the obligations of the MIT license, should also follow the obligation to retain the copyright information of ZLMediaKit software.
|
||||
* Users may not remove the "ZLMediaKit" information from the various services provided by ZLMediaKit, including but not limited to the "title", "Server", "User-Agent" fields.
|
||||
* Otherwise, the main rights holder of this project (project initiator, main author) reserves the right to claim and sue.
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:f214f734]
|
||||
*/
|
||||
#if !defined(ENABLE_VERSION)
|
||||
const char kServerName[] = "ZLMediaKit-8.0(build in " __DATE__ " " __TIME__ ")";
|
||||
|
@ -19,7 +19,8 @@ using namespace std;
|
||||
|
||||
namespace mediakit {
|
||||
|
||||
//////////////////////////通用///////////////////////
|
||||
// ////////////////////////通用/////////////////////// [AUTO-TRANSLATED:758fb788]
|
||||
// ////////////////////////General///////////////////////
|
||||
void UTF8ToUnicode(wchar_t *pOut, const char *pText) {
|
||||
char *uchar = (char *) pOut;
|
||||
uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F);
|
||||
@ -28,7 +29,8 @@ void UTF8ToUnicode(wchar_t *pOut, const char *pText) {
|
||||
}
|
||||
|
||||
void UnicodeToUTF8(char *pOut, const wchar_t *pText) {
|
||||
// 注意 WCHAR高低字的顺序,低字节在前,高字节在后
|
||||
// 注意 WCHAR高低字的顺序,低字节在前,高字节在后 [AUTO-TRANSLATED:95408ed0]
|
||||
// Note the order of the high and low bytes of WCHAR, the low byte is in front, and the high byte is behind
|
||||
const char *pchar = (const char *) pText;
|
||||
pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
|
||||
pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
|
||||
@ -47,7 +49,8 @@ char HexStrToBin(const char *str) {
|
||||
auto high = HexCharToBin(str[0]);
|
||||
auto low = HexCharToBin(str[1]);
|
||||
if (high == -1 || low == -1) {
|
||||
// 无法把16进制字符串转换为二进制
|
||||
// 无法把16进制字符串转换为二进制 [AUTO-TRANSLATED:2c828a6f]
|
||||
// Cannot convert hexadecimal string to binary
|
||||
return -1;
|
||||
}
|
||||
return (high << 4) | low;
|
||||
@ -73,13 +76,15 @@ static string UrlDecodeCommon(const string &str,const char* dont_unescape){
|
||||
while (i < len) {
|
||||
if (str[i] == '%') {
|
||||
if (i + 3 > len) {
|
||||
// %后面必须还有两个字节才会反转义
|
||||
// %后面必须还有两个字节才会反转义 [AUTO-TRANSLATED:c7c4299a]
|
||||
// There must be two bytes after % to escape
|
||||
output.append(str, i, len - i);
|
||||
break;
|
||||
}
|
||||
char ch = HexStrToBin(&(str[i + 1]));
|
||||
if (ch == -1 || strchr(dont_unescape, (unsigned char)ch) != NULL) {
|
||||
// %后面两个字节不是16进制字符串,转义失败;或者转义出来可能会造成url包含非path部分,比如#?,说明提交的是非法拼接的url;直接拼接3个原始字符
|
||||
// %后面两个字节不是16进制字符串,转义失败;或者转义出来可能会造成url包含非path部分,比如#?,说明提交的是非法拼接的url;直接拼接3个原始字符 [AUTO-TRANSLATED:7c734054]
|
||||
// The two bytes after % are not hexadecimal strings, the escape fails; or the escaped result may cause the url to contain non-path parts, such as #?, indicating that the submitted url is illegally spliced; directly splice the three original characters
|
||||
output.append(str, i, 3);
|
||||
} else {
|
||||
output += ch;
|
||||
@ -105,10 +110,13 @@ string strCoding::UrlEncodeComponent(const string &str) {
|
||||
|
||||
std::string strCoding::UrlEncodeUserOrPass(const std::string &str) {
|
||||
// from rfc https://datatracker.ietf.org/doc/html/rfc3986
|
||||
// §2.3 Unreserved characters (mark) [AUTO-TRANSLATED:d9a6a1d3]
|
||||
// §2.3 Unreserved characters (mark)
|
||||
//'-', '_', '.', '~'
|
||||
// §2.2 Reserved characters (reserved) [AUTO-TRANSLATED:4da0c164]
|
||||
// §2.2 Reserved characters (reserved)
|
||||
// '$', '&', '+', ',', '/', ':', ';', '=', '?', '@',
|
||||
// §3.2.1 [AUTO-TRANSLATED:f282bdcd]
|
||||
// §3.2.1
|
||||
// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
|
||||
// userinfo, so we must escape only '@', '/', and '?'.
|
||||
@ -129,13 +137,15 @@ std::string strCoding::UrlDecodeComponent(const std::string &str) {
|
||||
while (i < len) {
|
||||
if (str[i] == '%') {
|
||||
if (i + 3 > len) {
|
||||
// %后面必须还有两个字节才会反转义
|
||||
// %后面必须还有两个字节才会反转义 [AUTO-TRANSLATED:c7c4299a]
|
||||
// There must be two bytes after % to escape
|
||||
output.append(str, i, len - i);
|
||||
break;
|
||||
}
|
||||
char ch = HexStrToBin(&(str[i + 1]));
|
||||
if (ch == -1) {
|
||||
// %后面两个字节不是16进制字符串,转义失败;直接拼接3个原始字符
|
||||
// %后面两个字节不是16进制字符串,转义失败;直接拼接3个原始字符 [AUTO-TRANSLATED:10e614a4]
|
||||
// The two bytes after % are not hexadecimal strings, the escape fails; directly splice the three original characters
|
||||
output.append(str, i, 3);
|
||||
} else {
|
||||
output += ch;
|
||||
@ -157,7 +167,8 @@ std::string strCoding::UrlDecodeUserOrPass(const std::string &str) {
|
||||
const char *dont_unescape = "";
|
||||
return UrlDecodeCommon(str,dont_unescape);
|
||||
}
|
||||
///////////////////////////////windows专用///////////////////////////////////
|
||||
// /////////////////////////////windows专用/////////////////////////////////// [AUTO-TRANSLATED:e6109cf5]
|
||||
// /////////////////////////////Windows Specific///////////////////////////////////
|
||||
#if defined(_WIN32)
|
||||
void UnicodeToGB2312(char* pOut, wchar_t uData)
|
||||
{
|
||||
@ -208,7 +219,8 @@ string strCoding::GB2312ToUTF8(const string &str) {
|
||||
size_t i = 0, j = 0;
|
||||
while (i < len)
|
||||
{
|
||||
//如果是英文直接复制就可以
|
||||
// 如果是英文直接复制就可以 [AUTO-TRANSLATED:d6abdf68]
|
||||
// If it is English, you can copy it directly
|
||||
if (*(pText + i) >= 0)
|
||||
{
|
||||
pOut[j++] = pText[i++];
|
||||
|
@ -18,6 +18,9 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* 通用 rtmp解码类
|
||||
* Generic rtmp decoder class
|
||||
|
||||
* [AUTO-TRANSLATED:b04614f4]
|
||||
*/
|
||||
class CommonRtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@ -25,18 +28,28 @@ public:
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* Constructor
|
||||
|
||||
* [AUTO-TRANSLATED:41469869]
|
||||
*/
|
||||
CommonRtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入Rtmp并解码
|
||||
* @param rtmp Rtmp数据包
|
||||
* Input Rtmp and decode
|
||||
* @param rtmp Rtmp data packet
|
||||
|
||||
* [AUTO-TRANSLATED:43b1eae8]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* 通用 rtmp编码类
|
||||
* Generic rtmp encoder class
|
||||
|
||||
* [AUTO-TRANSLATED:4616a2a8]
|
||||
*/
|
||||
class CommonRtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@ -46,6 +59,10 @@ public:
|
||||
|
||||
/**
|
||||
* 输入帧数据
|
||||
* Input frame data
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:d13bc7f2]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
|
@ -26,7 +26,8 @@ void CommonRtpDecoder::obtainFrame() {
|
||||
bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual load
|
||||
return false;
|
||||
}
|
||||
auto payload = rtp->getPayload();
|
||||
@ -34,19 +35,23 @@ bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){
|
||||
auto seq = rtp->getSeq();
|
||||
|
||||
if (_last_stamp != stamp || _frame->_buffer.size() > _max_frame_size) {
|
||||
//时间戳发生变化或者缓存超过MAX_FRAME_SIZE,则清空上帧数据
|
||||
// 时间戳发生变化或者缓存超过MAX_FRAME_SIZE,则清空上帧数据 [AUTO-TRANSLATED:96f15576]
|
||||
// If the timestamp changes or the cache exceeds MAX_FRAME_SIZE, clear the previous frame data
|
||||
if (!_frame->_buffer.empty()) {
|
||||
//有有效帧,则输出
|
||||
// 有有效帧,则输出 [AUTO-TRANSLATED:f3ff1bda]
|
||||
// If there is a valid frame, output it
|
||||
RtpCodec::inputFrame(_frame);
|
||||
}
|
||||
|
||||
//新的一帧数据
|
||||
// 新的一帧数据 [AUTO-TRANSLATED:5b5f3a35]
|
||||
// New frame data
|
||||
obtainFrame();
|
||||
_frame->_dts = rtp->getStampMS();
|
||||
_last_stamp = stamp;
|
||||
_drop_flag = false;
|
||||
} else if (_last_seq != 0 && (uint16_t)(_last_seq + 1) != seq) {
|
||||
//时间戳未发生变化,但是seq却不连续,说明中间rtp丢包了,那么整帧应该废弃
|
||||
// 时间戳未发生变化,但是seq却不连续,说明中间rtp丢包了,那么整帧应该废弃 [AUTO-TRANSLATED:577bf835]
|
||||
// If the timestamp does not change, but the seq is not continuous, it means that the RTP packet has been lost in the middle, so the entire frame should be discarded
|
||||
WarnL << "rtp丢包:" << _last_seq << " -> " << seq;
|
||||
_drop_flag = true;
|
||||
_frame->_buffer.clear();
|
||||
|
@ -18,6 +18,9 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* 通用 rtp解码类
|
||||
* Generic rtp decoder class
|
||||
|
||||
* [AUTO-TRANSLATED:41b57089]
|
||||
*/
|
||||
class CommonRtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@ -27,6 +30,11 @@ public:
|
||||
* 构造函数
|
||||
* @param codec 编码id
|
||||
* @param max_frame_size 允许的最大帧大小
|
||||
* Constructor
|
||||
* @param codec codec id
|
||||
* @param max_frame_size maximum allowed frame size
|
||||
|
||||
* [AUTO-TRANSLATED:c6b0414f]
|
||||
*/
|
||||
CommonRtpDecoder(CodecId codec, size_t max_frame_size = 2 * 1024);
|
||||
|
||||
@ -34,6 +42,11 @@ public:
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
* Input rtp and decode
|
||||
* @param rtp rtp data packet
|
||||
* @param key_pos This parameter is internally forced to false, please ignore it
|
||||
|
||||
* [AUTO-TRANSLATED:2993fcbe]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
@ -51,6 +64,9 @@ private:
|
||||
|
||||
/**
|
||||
* 通用 rtp编码类
|
||||
* Generic rtp encoder class
|
||||
|
||||
* [AUTO-TRANSLATED:bb3991a5]
|
||||
*/
|
||||
class CommonRtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@ -58,6 +74,10 @@ public:
|
||||
|
||||
/**
|
||||
* 输入帧数据并编码成rtp
|
||||
* Input frame data and encode into rtp
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:02bc9009]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
};
|
||||
|
@ -45,7 +45,8 @@ void Factory::registerPlugin(const CodecPlugin &plugin) {
|
||||
Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
auto codec = getCodecId(track->_codec);
|
||||
if (codec == CodecInvalid) {
|
||||
// 根据传统的payload type 获取编码类型以及采样率等信息
|
||||
// 根据传统的payload type 获取编码类型以及采样率等信息 [AUTO-TRANSLATED:d01ca068]
|
||||
// Get the encoding type, sampling rate, and other information based on the traditional payload type
|
||||
codec = RtpPayload::getCodecId(track->_pt);
|
||||
}
|
||||
auto it = s_plugins.find(codec);
|
||||
@ -83,7 +84,8 @@ RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) {
|
||||
return it->second->getRtpDecoderByCodecId();
|
||||
}
|
||||
|
||||
/////////////////////////////rtmp相关///////////////////////////////////////////
|
||||
// ///////////////////////////rtmp相关/////////////////////////////////////////// [AUTO-TRANSLATED:da9645df]
|
||||
// ///////////////////////////rtmp related///////////////////////////////////////////
|
||||
|
||||
static CodecId getVideoCodecIdByAmf(const AMFValue &val){
|
||||
if (val.type() == AMF_STRING) {
|
||||
@ -197,7 +199,8 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) {
|
||||
Frame::Ptr Factory::getFrameFromPtr(CodecId codec, const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
|
||||
auto it = s_plugins.find(codec);
|
||||
if (it == s_plugins.end()) {
|
||||
// 创建不支持codec的frame
|
||||
// 创建不支持codec的frame [AUTO-TRANSLATED:00936c6c]
|
||||
// Create a frame that does not support the codec
|
||||
return std::make_shared<FrameFromPtr>(codec, (char *)data, bytes, dts, pts);
|
||||
}
|
||||
return it->second->getFrameFromPtr(data, bytes, dts, pts);
|
||||
|
@ -44,6 +44,9 @@ class Factory {
|
||||
public:
|
||||
/**
|
||||
* 注册插件,非线程安全的
|
||||
* Register plugin, not thread-safe
|
||||
|
||||
* [AUTO-TRANSLATED:43e22d01]
|
||||
*/
|
||||
static void registerPlugin(const CodecPlugin &plugin);
|
||||
|
||||
@ -53,17 +56,31 @@ public:
|
||||
* @param sample_rate 采样率,视频固定为90000
|
||||
* @param channels 音频通道数
|
||||
* @param sample_bit 音频采样位数
|
||||
* Get track by codec_id
|
||||
* @param codecId codec id
|
||||
* @param sample_rate sample rate, video is fixed to 90000
|
||||
* @param channels number of audio channels
|
||||
* @param sample_bit audio sample bit
|
||||
|
||||
* [AUTO-TRANSLATED:397b982e]
|
||||
*/
|
||||
static Track::Ptr getTrackByCodecId(CodecId codecId, int sample_rate = 0, int channels = 0, int sample_bit = 0);
|
||||
|
||||
// //////////////////////////////rtsp相关////////////////////////////////// [AUTO-TRANSLATED:884055ec]
|
||||
// //////////////////////////////rtsp相关//////////////////////////////////
|
||||
/**
|
||||
* 根据sdp生成Track对象
|
||||
* Generate Track object based on sdp
|
||||
|
||||
* [AUTO-TRANSLATED:79a99990]
|
||||
*/
|
||||
static Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track);
|
||||
|
||||
/**
|
||||
* 根据c api 抽象的Track生成具体Track对象
|
||||
* Generate specific Track object based on Track abstracted from c api
|
||||
|
||||
* [AUTO-TRANSLATED:991e7721]
|
||||
*/
|
||||
static Track::Ptr getTrackByAbstractTrack(const Track::Ptr& track);
|
||||
|
||||
@ -71,43 +88,72 @@ public:
|
||||
* 根据codec id生成rtp编码器
|
||||
* @param codec_id 编码id
|
||||
* @param pt rtp payload type
|
||||
* Generate rtp encoder based on codec id
|
||||
* @param codec_id codec id
|
||||
* @param pt rtp payload type
|
||||
|
||||
* [AUTO-TRANSLATED:3895b39c]
|
||||
*/
|
||||
static RtpCodec::Ptr getRtpEncoderByCodecId(CodecId codec_id, uint8_t pt);
|
||||
|
||||
/**
|
||||
* 根据Track生成Rtp解包器
|
||||
* Generate Rtp unpacker based on Track
|
||||
|
||||
* [AUTO-TRANSLATED:50dbf826]
|
||||
*/
|
||||
static RtpCodec::Ptr getRtpDecoderByCodecId(CodecId codec);
|
||||
|
||||
|
||||
// //////////////////////////////rtmp相关////////////////////////////////// [AUTO-TRANSLATED:df02d6fb]
|
||||
// //////////////////////////////rtmp相关//////////////////////////////////
|
||||
|
||||
/**
|
||||
* 根据amf对象获取视频相应的Track
|
||||
* @param amf rtmp metadata中的videocodecid的值
|
||||
* Get the corresponding video Track based on the amf object
|
||||
* @param amf the value of videocodecid in rtmp metadata
|
||||
|
||||
* [AUTO-TRANSLATED:c0c632c1]
|
||||
*/
|
||||
static Track::Ptr getVideoTrackByAmf(const AMFValue &amf);
|
||||
|
||||
/**
|
||||
* 根据amf对象获取音频相应的Track
|
||||
* @param amf rtmp metadata中的audiocodecid的值
|
||||
* Get the corresponding audio Track based on the amf object
|
||||
* @param amf the value of audiocodecid in rtmp metadata
|
||||
|
||||
* [AUTO-TRANSLATED:fc34f9e4]
|
||||
*/
|
||||
static Track::Ptr getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int channels, int sample_bit);
|
||||
|
||||
/**
|
||||
* 根据Track获取Rtmp的编码器
|
||||
* @param track 媒体描述对象
|
||||
* Get the Rtmp encoder based on Track
|
||||
* @param track media description object
|
||||
|
||||
* [AUTO-TRANSLATED:81fc38af]
|
||||
*/
|
||||
static RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track);
|
||||
|
||||
/**
|
||||
* 根据Track获取Rtmp的解码器
|
||||
* @param track 媒体描述对象
|
||||
* Get the Rtmp decoder based on Track
|
||||
* @param track media description object
|
||||
|
||||
* [AUTO-TRANSLATED:0744b09e]
|
||||
*/
|
||||
static RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track);
|
||||
|
||||
/**
|
||||
* 根据codecId获取rtmp的codec描述
|
||||
* Get the rtmp codec description based on codecId
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:67c749b7]
|
||||
*/
|
||||
static AMFValue getAmfByCodecId(CodecId codecId);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user