文章目录
- 1.开发背景
- 2.开始移植
- 3.小结
1.开发背景
目前市面上的流媒体服务程序大多以C/C++等编写的,而是用java编写的功能完善的流媒体服务几乎没有。对于有流媒体需求的java项目而言只能采用单独部署的方式并采用http及hook来进行业务交互,一定程度上增加了运维及开发的成本,所以开发或者移植一款功能齐全的流媒体服务势在必行。经过研究开发一款流媒体服务确实不太现实,正好开源流媒体服务框架ZLMediaKit提供二次开发SDK,所以我们采用ZLMediaKit C Api使用JNA技术翻译成Java Api。
2.开始移植
总共分为三步,第一步编译并构建ZLMediaKit C Api的动态链接库,第二步根据ZLMediaKit C Api的头文件封装Java代码中形成 ZLMApi,第三步使用ZLMApi构建自己的流媒体服务。编译和构建ZLMediaKit C Api的动态链接库可以参见ZLM的文档,封装头文件和如何使用参见下面代码。
封装头文件到java中
public interface ZLMApi extends Library {
/*******************************初始化与配置相关**********************************/
/**
* 初始化环境,调用该库前需要先调用此函数
*
* @param cfg 库运行相关参数
*/
void mk_env_init(MK_CONFIG cfg);
/**
* 服务器初始化
*
* @param thread_num
* @param log_level
* @param log_mask
* @param log_file_path
* @param log_file_days
* @param ini_is_path
* @param ini
* @param ssl_is_path
* @param ssl
* @param ssl_pwd
*/
void mk_env_init1(int thread_num, int log_level, int log_mask, String log_file_path, int log_file_days, int ini_is_path, Pointer ini, int ssl_is_path, String ssl, String ssl_pwd);
/**
* 创建ini配置对象
*/
MK_INI mk_ini_create();
/**
* 返回全局默认ini配置
*
* @return 全局默认ini配置,请勿用mk_ini_release释放它
*/
MK_INI mk_ini_default();
/**
* 加载ini配置文件内容
*
* @param ini ini对象
* @param str 配置文件内容
*/
void mk_ini_load_string(MK_INI ini, String str);
/**
* 加载ini配置文件
*
* @param ini ini对象
* @param file 配置文件路径
*/
void mk_ini_load_file(MK_INI ini, String file);
/**
* 销毁ini配置对象
*/
void mk_ini_release(MK_INI ini);
/**
* 导出为配置文件内容
*
* @param ini 配置对象
* @return 配置文件内容字符串,用完后需要自行mk_free
*/
Pointer mk_ini_dump_string(MK_INI ini);
/**
* 导出配置文件到文件
*
* @param ini 配置对象
* @param file 配置文件路径
*/
void mk_ini_dump_file(MK_INI ini, String file);
/**
* 添加或覆盖配置项
*
* @param ini 配置对象
* @param key 配置名,两段式,如:field.key
* @param value 配置值
*/
void mk_ini_set_option(MK_INI ini, String key, String value);
void mk_ini_set_option_int(MK_INI ini, String key, int value);
/**
* 获取配置项
*
* @param ini 配置对象
* @param key 配置名,两段式,如:field.key
* @return 配置不存在返回NULL,否则返回配置值
*/
String mk_ini_get_option(MK_INI ini, String key);
/**
* 删除配置项
*
* @param ini 配置对象
* @param key 配置名,两段式,如:field.key
* @return 1: 成功,0: 该配置不存在
*/
int mk_ini_del_option(MK_INI ini, String key);
/**
* 释放mk api内部malloc的资源
*/
void mk_free(Pointer pointer);
/**
* 设置日志文件
*
* @param file_max_size 单个切片文件大小(MB)
* @param file_max_count 切片文件个数
*/
void mk_set_log(int file_max_size, int file_max_count);
/**
* 设置配置项
*
* @param key 配置项名
* @param val 配置项值
* @deprecated 请使用mk_ini_set_option替代
*/
void mk_set_option(String key, String val);
/**
* 获取配置项的值
*
* @param key 配置项名
* @deprecated 请使用mk_ini_get_option替代
*/
String mk_get_option(String key);
/**
* 创建http[s]服务器
*
* @param port htt监听端口,推荐80,传入0则随机分配
* @param ssl 是否为ssl类型服务器
* @return 0:失败,非0:端口号
*/
short mk_http_server_start(short port, int ssl);
/**
* 创建rtsp[s]服务器
*
* @param port rtsp监听端口,推荐554,传入0则随机分配
* @param ssl 是否为ssl类型服务器
* @return 0:失败,非0:端口号
*/
short mk_rtsp_server_start(short port, int ssl);
/**
* 创建rtmp[s]服务器
*
* @param port rtmp监听端口,推荐1935,传入0则随机分配
* @param ssl 是否为ssl类型服务器
* @return 0:失败,非0:端口号
*/
short mk_rtmp_server_start(short port, int ssl);
/**
* 创建rtp服务器
*
* @param port rtp监听端口(包括udp/tcp)
* @return 0:失败,非0:端口号
*/
short mk_rtp_server_start(short port);
/**
* 创建rtc服务器
*
* @param port rtc监听端口
* @return 0:失败,非0:端口号
*/
short mk_rtc_server_start(short port);
/**
* webrtc交换sdp,根据offer sdp生成answer sdp
*
* @param user_data 回调用户指针
* @param cb 回调函数
* @param type webrtc插件类型,支持echo,play,push
* @param offer webrtc offer sdp
* @param url rtc url, 例如 rtc://__defaultVhost/app/stream?key1=val1&key2=val2
*/
void mk_webrtc_get_answer_sdp(Pointer user_data, IMKWebRtcGetAnwerSdpCallBack cb, String type, String offer, String url);
void mk_webrtc_get_answer_sdp2(Pointer user_data, IMKFreeUserDataCallBack user_data_free, IMKWebRtcGetAnwerSdpCallBack cb, String type, String offer, String url);
/**
* 创建srt服务器
*
* @param port srt监听端口
* @return 0:失败,非0:端口号
*/
short mk_srt_server_start(short port);
/**
* 创建shell服务器
*
* @param port shell监听端口
* @return 0:失败,非0:端口号
*/
short mk_shell_server_start(short port);
/**
* 关闭所有服务器,请在main函数退出时调用
*/
void mk_stop_all_server();
/*******************************流代理相关**********************************/
/**
* 创建一个代理播放器
*
* @param vhost 虚拟主机名,一般为__defaultVhost__
* @param app 应用名
* @param stream 流名
* @param hls_enabled 是否生成hls
* @param mp4_enabled 是否生成mp4
* @return 对象指针
*/
MK_PROXY_PLAYER mk_proxy_player_create(String vhost, String app, String stream, int hls_enabled, int mp4_enabled);
//MK_PROXY_PLAYER mk_proxy_player_create(String vhost, String app, String stream, int hls_enabled, int mp4_enabled, int fmp4_enabled, int ts_enabled, int rtmp_enabled, int rtsp_enabled);
/**
* 销毁代理播放器
*
* @param ctx 对象指针
*/
void mk_proxy_player_release(MK_PROXY_PLAYER ctx);
/**
* 开始播放
*
* @param ctx 对象指针
* @param url 播放url,支持rtsp/rtmp
*/
void mk_proxy_player_play(MK_PROXY_PLAYER ctx, String url);
/**
* 设置代理播放器配置选项
*
* @param ctx 代理播放器指针
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
* @param val 配置项值,如果是整形,需要转换成统一转换成string
*/
void mk_proxy_player_set_option(MK_PROXY_PLAYER ctx, String key, String val);
/**
* 监听MediaSource.close()事件
* 在选择关闭一个关联的MediaSource时,将会最终触发到该回调
* 你应该通过该事件调用mk_proxy_player_release函数并且释放其他资源
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_proxy_player_set_on_close(MK_PROXY_PLAYER ctx, IMKProxyPlayCloseCallBack cb, Pointer user_data);
void mk_proxy_player_set_on_close2(MK_PROXY_PLAYER ctx, IMKProxyPlayCloseCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 获取总的观看人数
*
* @param ctx 对象指针
* @return 观看人数
*/
int mk_proxy_player_total_reader_count(MK_PROXY_PLAYER ctx);
/*******************************RTP相关**********************************/
/**
* 创建GB28181 RTP 服务器
*
* @param port 监听端口,0则为随机
* @param tcp_mode tcp模式(0: 不监听端口 1: 监听端口 2: 主动连接到服务端)
* @param stream_id 该端口绑定的流id
* @return
*/
MK_RTP_SERVER mk_rtp_server_create(short port, int tcp_mode, String stream_id);
/**
* TCP 主动模式时连接到服务器
*
* @param @param ctx 服务器对象
* @param dst_url 服务端地址
* @param dst_port 服务端端口
* @param cb 连接到服务器是否成功的回调
* @param user_data 用户数据指针
* @return
*/
void mk_rtp_server_connect(MK_RTP_SERVER ctx, String dst_url, short dst_port, IMKRtpServerConnectedCallBack cb, Pointer user_data);
void mk_rtp_server_connect2(MK_RTP_SERVER ctx, String dst_url, short dst_port, IMKRtpServerConnectedCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 销毁GB28181 RTP 服务器
*
* @param ctx 服务器对象
*/
void mk_rtp_server_release(MK_RTP_SERVER ctx);
/**
* 获取本地监听的端口号
*
* @param ctx 服务器对象
* @return 端口号
*/
short mk_rtp_server_port(MK_RTP_SERVER ctx);
/**
* 监听B28181 RTP 服务器接收流超时事件
*
* @param ctx 服务器对象
* @param cb 回调函数
* @param user_data 回调函数用户数据指针
*/
void mk_rtp_server_set_on_detach(MK_RTP_SERVER ctx, IMKRtpServerDetachCallBack cb, Pointer user_data);
void mk_rtp_server_set_on_detach2(MK_RTP_SERVER ctx, IMKRtpServerDetachCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/*******************************播放相关**********************************/
/**
* 创建一个媒体源
*
* @param vhost 虚拟主机名,一般为__defaultVhost__
* @param app 应用名,推荐为live
* @param stream 流id,例如camera
* @param duration 时长(单位秒),直播则为0
* @param hls_enabled 是否生成hls
* @param mp4_enabled 是否生成mp4
* @return 对象指针
*/
MK_MEDIA mk_media_create(String vhost, String app, String stream, float duration, int hls_enabled, int mp4_enabled);
/**
* 创建一个媒体源
*
* @param vhost 虚拟主机名,一般为__defaultVhost__
* @param app 应用名,推荐为live
* @param stream 流id,例如camera
* @param duration 时长(单位秒),直播则为0
* @param option ProtocolOption相关配置
* @return 对象指针
*/
MK_MEDIA mk_media_create2(String vhost, String app, String stream, float duration, MK_INI option);
/**
* 销毁媒体源
*
* @param ctx 对象指针
*/
void mk_media_release(MK_MEDIA ctx);
/**
* 添加音视频track
*
* @param ctx mk_media对象
* @param track mk_track对象,音视频轨道
*/
void mk_media_init_track(MK_MEDIA ctx, MK_TRACK track);
/**
* 添加视频轨道,请改用mk_media_init_track方法
*
* @param ctx 对象指针
* @param codec_id 0:CodecH264/1:CodecH265
* @param width 视频宽度; 在编码时才有效
* @param height 视频高度; 在编码时才有效
* @param fps 视频fps; 在编码时才有效
* @param bit_rate 视频比特率,单位bps; 在编码时才有效
* @param width 视频宽度
* @param height 视频高度
* @param fps 视频fps
* @return 1代表成功,0失败
*/
int mk_media_init_video(MK_MEDIA ctx, int codec_id, int width, int height, float fps, int bit_rate);
/**
* 添加音频轨道,请改用mk_media_init_track方法
*
* @param ctx 对象指针
* @param codec_id 2:CodecAAC/3:CodecG711A/4:CodecG711U/5:OPUS
* @param channels 通道数
* @param sample_bit 采样位数,只支持16
* @param sample_rate 采样率
* @return 1代表成功,0失败
*/
int mk_media_init_audio(MK_MEDIA ctx, int codec_id, int sample_rate, int channels, int sample_bit);
/**
* 初始化h264/h265/aac完毕后调用此函数,
* 在单track(只有音频或视频)时,因为ZLMediaKit不知道后续是否还要添加track,所以会多等待3秒钟
* 如果产生的流是单Track类型,请调用此函数以便加快流生成速度,当然不调用该函数,影响也不大(会多等待3秒)
*
* @param ctx 对象指针
*/
void mk_media_init_complete(MK_MEDIA ctx);
/**
* 输入frame对象
*
* @param ctx mk_media对象
* @param frame 帧对象
* @return 1代表成功,0失败
*/
int mk_media_input_frame(MK_MEDIA ctx, MK_FRAME frame);
/**
* 输入单帧H264视频,帧起始字节00 00 01,00 00 00 01均可,请改用mk_media_input_frame方法
*
* @param ctx 对象指针
* @param data 单帧H264数据
* @param len 单帧H264数据字节数
* @param dts 解码时间戳,单位毫秒
* @param pts 播放时间戳,单位毫秒
* @return 1代表成功,0失败
*/
int mk_media_input_h264(MK_MEDIA ctx, Pointer data, int len, long dts, long pts);
/**
* 输入单帧H265视频,帧起始字节00 00 01,00 00 00 01均可,请改用mk_media_input_frame方法
*
* @param ctx 对象指针
* @param data 单帧H265数据
* @param len 单帧H265数据字节数
* @param dts 解码时间戳,单位毫秒
* @param pts 播放时间戳,单位毫秒
* @return 1代表成功,0失败
*/
int mk_media_input_h265(MK_MEDIA ctx, Pointer data, int len, long dts, long pts);
/**
* 输入YUV视频数据
*
* @param ctx 对象指针
* @param yuv yuv420p数据
* @param linesize yuv420p linesize
* @param cts 视频采集时间戳,单位毫秒
*/
void mk_media_input_yuv(MK_MEDIA ctx, String yuv[], int linesize[], long cts);
/**
* 输入单帧AAC音频(单独指定adts头),请改用mk_media_input_frame方法
*
* @param ctx 对象指针
* @param data 不包含adts头的单帧AAC数据,adts头7个字节
* @param len 单帧AAC数据字节数
* @param dts 时间戳,毫秒
* @param adts adts头,可以为null
* @return 1代表成功,0失败
*/
int mk_media_input_aac(MK_MEDIA ctx, Pointer data, int len, long dts, Pointer adts);
/**
* 输入单帧PCM音频,启用ENABLE_FAAC编译时,该函数才有效
*
* @param ctx 对象指针
* @param data 单帧PCM数据
* @param len 单帧PCM数据字节数
* @param pts 时间戳,毫秒
* @return 1代表成功,0失败
*/
int mk_media_input_pcm(MK_MEDIA ctx, Pointer data, int len, long pts);
/**
* 输入单帧OPUS/G711音频帧,请改用mk_media_input_frame方法
*
* @param ctx 对象指针
* @param data 单帧音频数据
* @param len 单帧音频数据字节数
* @param dts 时间戳,毫秒
* @return 1代表成功,0失败
*/
int mk_media_input_audio(MK_MEDIA ctx, Pointer data, int len, long dts);
/**
* 监听MediaSource.close()事件
* 在选择关闭一个关联的MediaSource时,将会最终触发到该回调
* 你应该通过该事件调用mk_media_release函数并且释放其他资源
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_media_set_on_close(MK_MEDIA ctx, IMKCloseEventCallBack cb, Pointer user_data);
void mk_media_set_on_close2(MK_MEDIA ctx, IMKCloseEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 监听播放器seek请求事件
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_media_set_on_seek(MK_MEDIA ctx, IMKSeekEventCallBack cb, Pointer user_data);
void mk_media_set_on_seek2(MK_MEDIA ctx, IMKSeekEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 监听播放器pause请求事件
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_media_set_on_pause(MK_MEDIA ctx, IMKPauseEventCallBack cb, Pointer user_data);
void mk_media_set_on_pause2(MK_MEDIA ctx, IMKPauseEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 监听播放器pause请求事件
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_media_set_on_speed(MK_MEDIA ctx, IMKSpeedEventCallBack cb, Pointer user_data);
void mk_media_set_on_speed2(MK_MEDIA ctx, IMKSpeedEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 获取总的观看人数
*
* @param ctx 对象指针
* @return 观看人数
*/
int mk_media_total_reader_count(MK_MEDIA ctx);
/**
* 设置MediaSource注册或注销事件回调函数
*
* @param ctx 对象指针
* @param cb 回调指针
* @param user_data 用户数据指针
*/
void mk_media_set_on_regist(MK_MEDIA ctx, IMKSourceRegisterEventCallBack cb, Pointer user_data);
void mk_media_set_on_regist2(MK_MEDIA ctx, IMKSourceRegisterEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 开始发送一路ps-rtp流(通过ssrc区分多路),此api线程安全
*
* @param ctx 对象指针
* @param dst_url 目标ip或域名
* @param dst_port 目标端口
* @param ssrc rtp的ssrc,10进制的字符串打印
* @param is_udp 是否为udp
* @param cb 启动成功或失败回调
* @param user_data 回调用户指针
*/
void mk_media_start_send_rtp(MK_MEDIA ctx, String dst_url, short dst_port, String ssrc, int is_udp, IMKSourceSendRtpResultCallBack cb, Pointer user_data);
void mk_media_start_send_rtp2(MK_MEDIA ctx, String dst_url, short dst_port, String ssrc, int is_udp, IMKSourceSendRtpResultCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 停止某路或全部ps-rtp发送,此api线程安全
*
* @param ctx 对象指针
* @param ssrc rtp的ssrc,10进制的字符串打印,如果为null或空字符串,则停止所有rtp推流
*/
void mk_media_stop_send_rtp(MK_MEDIA ctx, String ssrc);
/**
* 获取所属线程
*
* @param ctx 对象指针
*/
MK_THREAD mk_media_get_owner_thread(MK_MEDIA ctx);
/*******************************轨道相关**********************************/
/**
* 创建track对象引用
*
* @param codec_id 请参考MKCodecXXX 常量定义
* @param args 视频或音频参数
* @return track对象引用
*/
MK_TRACK mk_track_create(int codec_id, CodecArgs args);
/**
* 减引用track对象
*
* @param track track对象
*/
void mk_track_unref(MK_TRACK track);
/**
* 引用track对象
*
* @param track track对象
* @return 新的track引用对象
*/
MK_TRACK mk_track_ref(MK_TRACK track);
/*
* 获取track 编码codec类型,请参考MKCodecXXX定义
*/
int mk_track_codec_id(MK_TRACK track);
/**
* 获取编码codec名称
*/
String mk_track_codec_name(MK_TRACK track);
/**
* 获取比特率信息
*/
int mk_track_bit_rate(MK_TRACK track);
/**
* track是否为视频
*/
int mk_track_is_video(MK_TRACK track);
/**
* 获取视频宽度
*/
int mk_track_video_width(MK_TRACK track);
/**
* 获取视频高度
*/
int mk_track_video_height(MK_TRACK track);
/**
* 获取视频帧率
*/
int mk_track_video_fps(MK_TRACK track);
/**
* 获取音频采样率
*/
int mk_track_audio_sample_rate(MK_TRACK track);
/**
* 获取音频通道数
*/
int mk_track_audio_channel(MK_TRACK track);
/**
* 获取音频位数,一般为16bit
*/
int mk_track_audio_sample_bit(MK_TRACK track);
/**
* 监听frame输出事件
*
* @param track track对象
* @param cb frame输出回调
* @param user_data frame输出回调用户指针参数
*/
void mk_track_add_delegate(MK_TRACK track, IMKFrameOutCallBack cb, Pointer user_data);
void mk_track_add_delegate2(MK_TRACK track, IMKFrameOutCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 取消frame输出事件监听
*
* @param track track对象
* @param tag mk_track_add_delegate返回值
*/
void mk_track_del_delegate(MK_TRACK track, Pointer tag);
/**
* 输入frame到track,通常你不需要调用此api
*/
void mk_track_input_frame(MK_TRACK track, MK_FRAME frame);
/*******************************推流相关**********************************/
/**
* 绑定的MediaSource对象并创建rtmp[s]/rtsp[s]推流器
* MediaSource通过mk_media_create或mk_proxy_player_create或推流生成
* 该MediaSource对象必须已注册
*
* @param schema 绑定的MediaSource对象所属协议,支持rtsp/rtmp
* @param vhost 绑定的MediaSource对象的虚拟主机,一般为__defaultVhost__
* @param app 绑定的MediaSource对象的应用名,一般为live
* @param stream 绑定的MediaSource对象的流id
* @return 对象指针
*/
MK_PUSHER mk_pusher_create(String schema, String vhost, String app, String stream);
/**
* 绑定的MediaSource对象并创建rtmp[s]/rtsp[s]推流器
* MediaSource通过mk_media_create或mk_proxy_player_create或推流生成
* 该MediaSource对象必须已注册
*
* @param src MediaSource对象
* @return 对象指针
*/
MK_PUSHER mk_pusher_create_src(MK_MEDIA_SOURCE src);
/**
* 释放推流器
*
* @param ctx 推流器指针
*/
void 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
*/
void mk_pusher_set_option(MK_PUSHER ctx, String key, String val);
/**
* 开始推流
*
* @param ctx 推流器指针
* @param url 推流地址,支持rtsp[s]/rtmp[s]
*/
void mk_pusher_publish(MK_PUSHER ctx, String url);
/**
* 设置推流器推流结果回调函数
*
* @param ctx 推流器指针
* @param cb 回调函数指针,不得为null
* @param user_data 用户数据指针
*/
void mk_pusher_set_on_result(MK_PUSHER ctx, IMKPushEventCallBack cb, Pointer user_data);
void mk_pusher_set_on_result2(MK_PUSHER ctx, IMKPushEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 设置推流被异常中断的回调
*
* @param ctx 推流器指针
* @param cb 回调函数指针,不得为null
* @param user_data 用户数据指针
*/
void mk_pusher_set_on_shutdown(MK_PUSHER ctx, IMKPushEventCallBack cb, Pointer user_data);
void mk_pusher_set_on_shutdown2(MK_PUSHER ctx, IMKPushEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/*******************************播放相关**********************************/
/**
* 创建一个播放器,支持rtmp[s]/rtsp[s]
*
* @return 播放器指针
*/
MK_PLAYER mk_player_create();
/**
* 销毁播放器
*
* @param ctx 播放器指针
*/
void 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
*/
void mk_player_set_option(MK_PLAYER ctx, String key, String val);
/**
* 开始播放url
*
* @param ctx 播放器指针
* @param url rtsp[s]/rtmp[s] url
*/
void mk_player_play(MK_PLAYER ctx, String url);
/**
* 暂停或恢复播放,仅对点播有用
*
* @param ctx 播放器指针
* @param pause 1:暂停播放,0:恢复播放
*/
void mk_player_pause(MK_PLAYER ctx, int pause);
/**
* 倍数播放,仅对点播有用
*
* @param ctx 播放器指针
* @param speed 0.5 1.0 2.0
*/
void mk_player_speed(MK_PLAYER ctx, float speed);
/**
* 设置点播进度条
*
* @param ctx 对象指针
* @param progress 取值范围未 0.0~1.0
*/
void mk_player_seekto(MK_PLAYER ctx, float progress);
/**
* 设置点播进度条
*
* @param ctx 对象指针
* @param seek_pos 取值范围 相对于开始时间增量 单位秒
*/
void mk_player_seekto_pos(MK_PLAYER ctx, int seek_pos);
/**
* 设置播放器开启播放结果回调函数
*
* @param ctx 播放器指针
* @param cb 回调函数指针,设置null立即取消回调
* @param user_data 用户数据指针
*/
void mk_player_set_on_result(MK_PLAYER ctx, IMKPlayEventCallBack cb, Pointer user_data);
void mk_player_set_on_result2(MK_PLAYER ctx, IMKPlayEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 设置播放被异常中断的回调
*
* @param ctx 播放器指针
* @param cb 回调函数指针,设置null立即取消回调
* @param user_data 用户数据指针
*/
void mk_player_set_on_shutdown(MK_PLAYER ctx, IMKPlayEventCallBack cb, Pointer user_data);
void mk_player_set_on_shutdown2(MK_PLAYER ctx, IMKPlayEventCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
///获取音视频相关信息接口在播放成功回调触发后才有效///
/**
* 获取点播节目时长,如果是直播返回0,否则返回秒数
*/
float mk_player_duration(MK_PLAYER ctx);
/**
* 获取点播播放进度,取值范围 0.0~1.0
*/
float mk_player_progress(MK_PLAYER ctx);
/**
* 获取点播播放进度位置,取值范围 相对于开始时间增量 单位秒
*/
int mk_player_progress_pos(MK_PLAYER ctx);
/**
* 获取丢包率,rtsp时有效
*
* @param ctx 对象指针
* @param track_type 0:视频,1:音频
*/
float mk_player_loss_rate(MK_PLAYER ctx, int track_type);
/*******************************录制相关**********************************/
/**
* 创建flv录制器
*
* @return
*/
MK_FLV_RECORDER mk_flv_recorder_create();
/**
* 释放flv录制器
*
* @param ctx
*/
void mk_flv_recorder_release(MK_FLV_RECORDER ctx);
/**
* 开始录制flv
*
* @param ctx flv录制器
* @param vhost 虚拟主机
* @param app 绑定的RtmpMediaSource的 app名
* @param stream 绑定的RtmpMediaSource的 stream名
* @param file_path 文件存放地址
* @return 0:开始超过,-1:失败,打开文件失败或该RtmpMediaSource不存在
*/
int mk_flv_recorder_start(MK_FLV_RECORDER ctx, String vhost, String app, String stream, String file_path);
///hls/mp4录制/
/**
* 获取录制状态
*
* @param type 0:hls,1:MP4
* @param vhost 虚拟主机
* @param app 应用名
* @param stream 流id
* @return 录制状态, 0:未录制, 1:正在录制
*/
int mk_recorder_is_recording(int type, String vhost, String app, String stream);
/**
* 开始录制
*
* @param type 0:hls-ts,1:MP4,2:hls-fmp4,3:http-fmp4,4:http-ts
* @param vhost 虚拟主机
* @param app 应用名
* @param stream 流id
* @param customized_path 录像文件保存自定义目录,默认为空或null则自动生成
* @param max_second mp4录制最大切片时间,单位秒,置0则采用配置文件配置
* @return 1代表成功,0代表失败
*/
int mk_recorder_start(int type, String vhost, String app, String stream, String customized_path, long max_second);
/**
* 停止录制
*
* @param type 0:hls-ts,1:MP4,2:hls-fmp4,3:http-fmp4,4:http-ts
* @param vhost 虚拟主机
* @param app 应用名
* @param stream 流id
* @return 1:成功,0:失败
*/
int mk_recorder_stop(int type, String vhost, String app, String stream);
/*******************************事件相关**********************************/
void mk_events_listen(MK_EVENTS events);
/*******************************结构体相关**********************************/
///MP4Info/
//MP4Info对象的C映射
// GMT 标准时间,单位秒
long mk_mp4_info_get_start_time(MK_MP4_INFO ctx);
// 录像长度,单位秒
float mk_mp4_info_get_time_len(MK_MP4_INFO ctx);
// 文件大小,单位 BYTE
long mk_mp4_info_get_file_size(MK_MP4_INFO ctx);
// 文件路径
String mk_mp4_info_get_file_path(MK_MP4_INFO ctx);
// 文件名称
String mk_mp4_info_get_file_name(MK_MP4_INFO ctx);
// 文件夹路径
String mk_mp4_info_get_folder(MK_MP4_INFO ctx);
// 播放路径
String mk_mp4_info_get_url(MK_MP4_INFO ctx);
// 应用名称
String mk_mp4_info_get_vhost(MK_MP4_INFO ctx);
// 流 ID
String mk_mp4_info_get_app(MK_MP4_INFO ctx);
// 虚拟主机
String mk_mp4_info_get_stream(MK_MP4_INFO ctx);
///Parser/
//Parser对象的C映射
//Parser::Method(),获取命令字,譬如GET/POST
String mk_parser_get_method(MK_PARSER ctx);
//Parser::Url(),获取HTTP的访问url(不包括?后面的参数)
String mk_parser_get_url(MK_PARSER ctx);
//Parser::Params(),?后面的参数字符串
String mk_parser_get_url_params(MK_PARSER ctx);
//Parser::getUrlArgs()["key"],获取?后面的参数中的特定参数
String mk_parser_get_url_param(MK_PARSER ctx, String key);
//Parser::Tail(),获取协议相关信息,譬如 HTTP/1.1
String mk_parser_get_tail(MK_PARSER ctx);
//Parser::getValues()["key"],获取HTTP头中特定字段
String mk_parser_get_header(MK_PARSER ctx, String key);
//Parser::Content(),获取HTTP body
String mk_parser_get_content(MK_PARSER ctx, long length);
///MediaInfo/
//MediaInfo对象的C映射
//MediaInfo::param_strs
String mk_media_info_get_params(MK_MEDIA_INFO ctx);
//MediaInfo::schema
String mk_media_info_get_schema(MK_MEDIA_INFO ctx);
//MediaInfo::vhost
String mk_media_info_get_vhost(MK_MEDIA_INFO ctx);
//MediaInfo::app
String mk_media_info_get_app(MK_MEDIA_INFO ctx);
//MediaInfo::stream
String mk_media_info_get_stream(MK_MEDIA_INFO ctx);
//MediaInfo::host
String mk_media_info_get_host(MK_MEDIA_INFO ctx);
//MediaInfo::port
short mk_media_info_get_port(MK_MEDIA_INFO ctx);
///MediaSource/
//MediaSource::getSchema()
String mk_media_source_get_schema(MK_MEDIA_SOURCE ctx);
//MediaSource::getVhost()
String mk_media_source_get_vhost(MK_MEDIA_SOURCE ctx);
//MediaSource::getApp()
String mk_media_source_get_app(MK_MEDIA_SOURCE ctx);
//MediaSource::getId()
String mk_media_source_get_stream(MK_MEDIA_SOURCE ctx);
//MediaSource::readerCount()
int mk_media_source_get_reader_count(MK_MEDIA_SOURCE ctx);
//MediaSource::totalReaderCount()
int mk_media_source_get_total_reader_count(MK_MEDIA_SOURCE ctx);
// get track count from MediaSource
int mk_media_source_get_track_count(MK_MEDIA_SOURCE ctx);
// copy track reference by index from MediaSource, please use mk_track_unref to release it
MK_TRACK mk_media_source_get_track(MK_MEDIA_SOURCE ctx, int index);
// MediaSource::broadcastMessage
int mk_media_source_broadcast_msg(MK_MEDIA_SOURCE ctx, String msg, long len);
/**
* 直播源在ZLMediaKit中被称作为MediaSource,
* 目前支持3种,分别是RtmpMediaSource、RtspMediaSource、HlsMediaSource
* 源的产生有被动和主动方式:
* 被动方式分别是rtsp/rtmp/rtp推流、mp4点播
* 主动方式包括mk_media_create创建的对象(DevChannel)、mk_proxy_player_create创建的对象(PlayerProxy)
* 被动方式你不用做任何处理,ZLMediaKit已经默认适配了MediaSource::close()事件,都会关闭直播流
* 主动方式你要设置这个事件的回调,你要自己选择删除对象
* 通过mk_proxy_player_set_on_close、mk_media_set_on_close函数可以设置回调,
* 请在回调中删除对象来完成媒体的关闭,否则又为什么要调用mk_media_source_close函数?
*
* @param ctx 对象
* @param force 是否强制关闭,如果强制关闭,在有人观看的情况下也会关闭
* @return 0代表失败,1代表成功
*/
int mk_media_source_close(MK_MEDIA_SOURCE ctx, int force);
//MediaSource::seekTo()
int mk_media_source_seek_to(MK_MEDIA_SOURCE ctx, int stamp);
/**
* rtp推流成功与否的回调(第一次成功后,后面将一直重试)
*/
//MediaSource::startSendRtp,请参考mk_media_start_send_rtp,注意ctx参数类型不一样
void mk_media_source_start_send_rtp(MK_MEDIA_SOURCE ctx, String dst_url, short dst_port, String ssrc, int is_udp, IMKSourceSendRtpResultCallBack cb, Pointer user_data);
void mk_media_source_start_send_rtp2(MK_MEDIA_SOURCE ctx, String dst_url, short dst_port, String ssrc, int is_udp, IMKSourceSendRtpResultCallBack cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
//MediaSource::stopSendRtp,请参考mk_media_stop_send_rtp,注意ctx参数类型不一样
int mk_media_source_stop_send_rtp(MK_MEDIA_SOURCE ctx);
//MediaSource::find()
void mk_media_source_find(String schema, String vhost, String app, String stream, int from_mp4, Pointer user_data, IMKSourceFindCallBack cb);
MK_MEDIA_SOURCE mk_media_source_find2(String schema, String vhost, String app, String stream, int from_mp4);
//MediaSource::for_each_media()
void mk_media_source_for_each(Pointer user_data, IMKSourceFindCallBack cb, String schema, String vhost, String app, String stream);
///HttpBody/
//HttpBody对象的C映射
/**
* 生成HttpStringBody
*
* @param str 字符串指针
* @param len 字符串长度,为0则用strlen获取
*/
MK_HTTP_BODY mk_http_body_from_string(String str, long len);
/**
* 生成HttpBufferBody
*
* @param buffer mk_buffer对象
*/
MK_HTTP_BODY mk_http_body_from_buffer(MK_BUFFER buffer);
/**
* 生成HttpFileBody
*
* @param file_path 文件完整路径
*/
MK_HTTP_BODY mk_http_body_from_file(String file_path);
/**
* 生成HttpMultiFormBody
*
* @param key_val 参数key-value
* @param file_path 文件完整路径
*/
MK_HTTP_BODY mk_http_body_from_multi_form(String key_val[], String file_path);
/**
* 销毁HttpBody
*/
void mk_http_body_release(MK_HTTP_BODY ctx);
///HttpResponseInvoker/
//HttpSession::HttpResponseInvoker对象的C映射
/**
* HttpSession::HttpResponseInvoker(const string &codeOut, const StrCaseMap &headerOut, const HttpBody::Ptr &body);
*
* @param response_code 譬如200
* @param response_header 返回的http头,譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
* @param response_body body对象
*/
void mk_http_response_invoker_do(MK_HTTP_RESPONSE_INVOKER ctx, int response_code, PointerByReference response_header, MK_HTTP_BODY response_body);
/**
* HttpSession::HttpResponseInvoker(const string &codeOut, const StrCaseMap &headerOut, const string &body);
*
* @param response_code 譬如200
* @param response_header 返回的http头,譬如 {"Content-Type","text/html",NULL} 必须以NULL结尾
* @param response_content 返回的content部分,譬如一个网页内容
*/
void mk_http_response_invoker_do_string(MK_HTTP_RESPONSE_INVOKER ctx, int response_code, PointerByReference response_header, String response_content);
/**
* HttpSession::HttpResponseInvoker(const StrCaseMap &requestHeader,const StrCaseMap &responseHeader,const string &filePath);
*
* @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
*/
void mk_http_response_invoker_do_file(MK_HTTP_RESPONSE_INVOKER ctx, MK_PARSER request_parser, String response_header[], String response_file_path);
/**
* 克隆mk_http_response_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_http_response_invoker_do
* 如果是同步执行mk_http_response_invoker_do,那么没必要克隆对象
*/
MK_HTTP_RESPONSE_INVOKER mk_http_response_invoker_clone(MK_HTTP_RESPONSE_INVOKER ctx);
/**
* 销毁堆上的克隆对象
*/
void mk_http_response_invoker_clone_release(MK_HTTP_RESPONSE_INVOKER ctx);
///HttpAccessPathInvoker/
//HttpSession::HttpAccessPathInvoker对象的C映射
/**
* HttpSession::HttpAccessPathInvoker(const string &errMsg,const string &accessPath, int cookieLifeSecond);
*
* @param err_msg 如果为空,则代表鉴权通过,否则为错误提示,可以为null
* @param access_path 运行或禁止访问的根目录,可以为null
* @param cookie_life_second 鉴权cookie有效期
**/
void mk_http_access_path_invoker_do(MK_HTTP_ACCESS_PATH_INVOKER ctx, String err_msg, String access_path, int cookie_life_second);
/**
* 克隆mk_http_access_path_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_http_access_path_invoker_do
* 如果是同步执行mk_http_access_path_invoker_do,那么没必要克隆对象
*/
MK_HTTP_ACCESS_PATH_INVOKER mk_http_access_path_invoker_clone(MK_HTTP_ACCESS_PATH_INVOKER ctx);
/**
* 销毁堆上的克隆对象
*/
void mk_http_access_path_invoker_clone_release(MK_HTTP_ACCESS_PATH_INVOKER ctx);
///RtspSession::onGetRealm/
//RtspSession::onGetRealm对象的C映射
/**
* 执行RtspSession::onGetRealm
*
* @param realm 该rtsp流是否需要开启rtsp专属鉴权,至null或空字符串则不鉴权
*/
void mk_rtsp_get_realm_invoker_do(MK_RTSP_GET_REALM_INVOKER ctx, String realm);
/**
* 克隆mk_rtsp_get_realm_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_rtsp_get_realm_invoker_do
* 如果是同步执行mk_rtsp_get_realm_invoker_do,那么没必要克隆对象
*/
MK_RTSP_GET_REALM_INVOKER mk_rtsp_get_realm_invoker_clone(MK_RTSP_GET_REALM_INVOKER ctx);
/**
* 销毁堆上的克隆对象
*/
void mk_rtsp_get_realm_invoker_clone_release(MK_RTSP_GET_REALM_INVOKER ctx);
///RtspSession::onAuth/
/**
* 执行RtspSession::onAuth
*
* @param encrypted 为true是则表明是md5加密的密码,否则是明文密码, 在请求明文密码时如果提供md5密码者则会导致认证失败
* @param pwd_or_md5 明文密码或者md5加密的密码
*/
void mk_rtsp_auth_invoker_do(MK_RTSP_AUTH_INVOKER ctx, int encrypted, String pwd_or_md5);
/**
* 克隆mk_rtsp_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_rtsp_auth_invoker_do
* 如果是同步执行mk_rtsp_auth_invoker_do,那么没必要克隆对象
*/
MK_RTSP_AUTH_INVOKER mk_rtsp_auth_invoker_clone(MK_RTSP_AUTH_INVOKER ctx);
/**
* 销毁堆上的克隆对象
*/
void mk_rtsp_auth_invoker_clone_release(MK_RTSP_AUTH_INVOKER ctx);
///Broadcast::PublishAuthInvoker/
//Broadcast::PublishAuthInvoker对象的C映射
/**
* 执行Broadcast::PublishAuthInvoker
*
* @param err_msg 为空或null则代表鉴权成功
* @param enable_hls 是否允许转换hls
* @param enable_mp4 是否运行MP4录制
*/
void mk_publish_auth_invoker_do(MK_PUBLISH_AUTH_INVOKER ctx, String err_msg, int enable_hls, int enable_mp4);
/**
* 克隆mk_publish_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_publish_auth_invoker_do
* 如果是同步执行mk_publish_auth_invoker_do,那么没必要克隆对象
*/
void mk_publish_auth_invoker_do2(MK_PUBLISH_AUTH_INVOKER ctx, String err_msg, MK_INI option);
/**
* 销毁堆上的克隆对象
*/
void mk_publish_auth_invoker_clone_release(MK_PUBLISH_AUTH_INVOKER ctx);
///Broadcast::AuthInvoker/
//Broadcast::AuthInvoker对象的C映射
/**
* 执行Broadcast::AuthInvoker
*
* @param err_msg 为空或null则代表鉴权成功
*/
void mk_auth_invoker_do(MK_AUTH_INVOKER ctx, String err_msg);
/**
* 克隆mk_auth_invoker对象,通过克隆对象为堆对象,可以实现跨线程异步执行mk_auth_invoker_do
* 如果是同步执行mk_auth_invoker_do,那么没必要克隆对象
*/
MK_AUTH_INVOKER mk_auth_invoker_clone(MK_AUTH_INVOKER ctx);
/**
* 销毁堆上的克隆对象
*/
void mk_auth_invoker_clone_release(MK_AUTH_INVOKER ctx);
/*******************************帧流相关**********************************/
/**
* 创建frame对象,并返回其引用
*
* @param codec_id 编解码类型,请参考MKCodecXXX定义
* @param dts 解码时间戳,单位毫秒
* @param pts 显示时间戳,单位毫秒
* @param data 单帧数据
* @param size 单帧数据长度
* @param cb data指针free释放回调, 如果为空,内部会拷贝数据
* @param user_data data指针free释放回调用户指针
* @return frame对象引用
*/
MK_FRAME mk_frame_create(int codec_id, long dts, long pts, Pointer data, long size,
IMKFrameDataRelease cb, Pointer user_data);
MK_FRAME mk_frame_create2(int codec_id, long dts, long pts, Pointer data, long size,
IMKFrameDataRelease cb, Pointer user_data, IMKFreeUserDataCallBack user_data_free);
/**
* 减引用frame对象
*
* @param frame 帧对象引用
*/
void mk_frame_unref(MK_FRAME frame);
/**
* 引用frame对象
*
* @param frame 被引用的frame对象
* @return 新的对象引用
*/
MK_FRAME mk_frame_ref(MK_FRAME frame);
/**
* 获取frame 编码codec类型,请参考MKCodecXXX定义
*/
int mk_frame_codec_id(MK_FRAME frame);
/**
* 获取帧编码codec名称
*/
String mk_frame_codec_name(MK_FRAME frame);
/**
* 帧是否为视频
*/
int mk_frame_is_video(MK_FRAME frame);
/**
* 获取帧数据指针
*/
String mk_frame_get_data(MK_FRAME frame);
/**
* 获取帧数据指针长度
*/
long mk_frame_get_data_size(MK_FRAME frame);
/**
* 返回帧数据前缀长度,譬如H264/H265前缀一般是0x00 00 00 01,那么本函数返回4
*/
long mk_frame_get_data_prefix_size(MK_FRAME frame);
/**
* 获取解码时间戳,单位毫秒
*/
long mk_frame_get_dts(MK_FRAME frame);
/**
* 获取显示时间戳,单位毫秒
*/
long mk_frame_get_pts(MK_FRAME frame);
/**
* 获取帧flag,请参考 MK_FRAME_FLAG
*/
int mk_frame_get_flags(MK_FRAME frame);
/**
* mpeg-ps/ts 打包器
*
* @param cb 打包回调函数
* @param user_data 回调用户数据指针
* @param is_ps 是否是ps
* @return 打包器对象
*/
MK_MPEG_MUXER mk_mpeg_muxer_create(IMKMpegMuxerFrameCallBack cb, Pointer user_data, int is_ps);
/**
* 删除mpeg-ps/ts 打包器
*
* @param ctx 打包器
*/
void mk_mpeg_muxer_release(MK_MPEG_MUXER ctx);
/**
* 添加音视频track
*
* @param ctx mk_mpeg_muxer对象
* @param track mk_track对象,音视频轨道
*/
void mk_mpeg_muxer_init_track(MK_MPEG_MUXER ctx, MK_TRACK track);
/**
* 初始化track完毕后调用此函数,
* 在单track(只有音频或视频)时,因为ZLMediaKit不知道后续是否还要添加track,所以会多等待3秒钟
* 如果产生的流是单Track类型,请调用此函数以便加快流生成速度,当然不调用该函数,影响也不大(会多等待3秒)
*
* @param ctx 对象指针
*/
void mk_mpeg_muxer_init_complete(MK_MPEG_MUXER ctx);
/**
* 输入frame对象
*
* @param ctx mk_mpeg_muxer对象
* @param frame 帧对象
* @return 1代表成功,0失败
*/
int mk_mpeg_muxer_input_frame(MK_MPEG_MUXER ctx, MK_FRAME frame);
}
使用ZLMApi构建自己的流媒体服务
public class Test {
//动态链接库放在/resource/win32-x86-64&/resource/linux-x86-64下JNA会自动查找目录
//public static ZLMApi ZLM_API = Native.load("mk_api", ZLMApi.class);
//Windows环境测试
public static ZLMApi ZLM_API = Native.load("D:\\ZLMediaKit\\source\\release\\windows\\Debug\\mk_api.dll", ZLMApi.class);
//Linux环境测试
//public static ZLMApi ZLM_API = Native.load("/opt/media/libmk_api.so", ZLMApi.class);
public static void main(String[] args) throws InterruptedException {
//初始化环境配置
MK_INI mkIni = ZLM_API.mk_ini_default();
//配置参数 全部配置参数及说明见(resources/conf.ini) 打开自动关流 对应conf.ini中配置[protocol] auto_close
ZLM_API.mk_ini_set_option_int(mkIni, "protocol.auto_close", 1);
ZLM_API.mk_ini_set_option_int(mkIni, "protocol.enable_fmp4", 0);
ZLM_API.mk_ini_set_option_int(mkIni, "protocol.enable_hls", 0);
ZLM_API.mk_ini_set_option_int(mkIni, "protocol.enable_ts", 0);
//全局回调 全部回调见MK_EVENTS内所有的回调属性,有些需要去实现,不然流无法播放或者无法推流
MK_EVENTS mkEvents = new MK_EVENTS();
//流状态改变回调
mkEvents.on_mk_media_changed = (regist, sender) -> {
System.out.println("这里是流改变回调通知:" + regist);
};
//无人观看回调
mkEvents.on_mk_media_no_reader = sender -> {
System.out.println("这里是无人观看回调通知");
ZLM_API.mk_media_source_close(sender, 1);
};
//播放回调可做播放鉴权
mkEvents.on_mk_media_play = (url_info, invoker, sender) -> {
//这里拿到访问路径后(例如http://xxxx/xxx/xxx.live.flv?token=xxxx其中?后面就是拿到的参数)的参数
// err_msg返回 空字符串表示鉴权成功 否则鉴权失败提示
//String param = ZLM_API.mk_media_info_get_params(url_info);
ZLM_API.mk_auth_invoker_do(invoker, "");
};
//推流回调 可控制鉴权、录制、转协议控制等
mkEvents.on_mk_media_publish = (url_info, invoker, sender) -> {
//这里拿到访问路径后(例如rtmp://xxxx/xxx/xxx?token=xxxx其中?后面就是拿到的参数)的参数
// err_msg返回 空字符串表示鉴权成功 否则鉴权失败提示
//String param = ZLM_API.mk_media_info_get_params(url_info);
ZLM_API.mk_publish_auth_invoker_do(invoker, "", 0, 0);
};
//添加全局回调
ZLM_API.mk_events_listen(mkEvents);
//Pointer iniPointer = ZLM_API.mk_ini_dump_string(mkIni);
//初始化zmk服务器
ZLM_API.mk_env_init1(1, 1, 1, null, 0, 0, null, 0, null, null);
//创建http服务器 0:失败,非0:端口号
short http_server_port = ZLM_API.mk_http_server_start((short) 7788, 0);
//创建rtsp服务器 0:失败,非0:端口号
short rtsp_server_port = ZLM_API.mk_rtsp_server_start((short) 554, 0);
//创建rtmp服务器 0:失败,非0:端口号
short rtmp_server_port = ZLM_API.mk_rtmp_server_start((short) 1935, 0);
/*****************************下面为推流及播放********************************/
// 推流:利用obs、ffmpeg 进行推流 RTMP推流:rtmp://127.0.0.1:rtmp_port/流APP/流名称 RTSP推流:rtsp://127.0.0.1:rtsp_port/流APP/流名称
// 下面是各协议拉流播放的访问格式
// FLV拉流:http://127.0.0.1:http_port/流APP/流名称.live.flv
// WS-FLV拉流:ws://127.0.0.1:http_port/流APP/流名称.live.flv
// HLS拉流:http://127.0.0.1:http_port/流APP/流名称/hls.m3u8
// RTMP拉流:rtmp://127.0.0.1:rtmp_port/流APP/流名称
// RTSP拉流:rtsp://127.0.0.1:rtsp_port/流APP/流名称
/*****************************下面为流代理演示********************************/
//创建拉流代理
MK_PROXY_PLAYER mk_proxy = ZLM_API.mk_proxy_player_create("__defaultVhost__", "live", "test", 0, 0);
//回调关闭时间
IMKProxyPlayCloseCallBack imkProxyPlayCloseCallBack = new IMKProxyPlayCloseCallBack() {
@Override
public void invoke(Pointer pUser, int err, String what, int sys_err) {
//这里Pointer是ZLM维护的不需要我们释放 遵循谁申请谁释放原则
ZLM_API.mk_proxy_player_release(new MK_PROXY_PLAYER(pUser));
}
};
//开始播放
ZLM_API.mk_proxy_player_play(mk_proxy, "rtsp://admin:admin@172.16.6.236/h264/ch1/main/av_stream");
//添加代理关闭回调 并把代理客户端传过去释放
ZLM_API.mk_proxy_player_set_on_close(mk_proxy, imkProxyPlayCloseCallBack, mk_proxy.getPointer());
/*****************************end********************************/
//阻塞60s
Thread.sleep(60000L);
//停止所有服务器
ZLM_API.mk_stop_all_server();
}
}
还有其他回调及结构体代码就不一一放出,放在项目j_zlm_sdk 中,并基于j_zlm_sdk用SpringBoot构建了一个java版本的ZLMediaKit项目代码参见 j_media_server,此项目可作为二次开发参考。j_zlm_sdk项目已被ZLMediaKit收录到wiki中。