赞
踩
目前市面上的流媒体服务程序大多以C/C++等编写的,而是用java编写的功能完善的流媒体服务几乎没有。对于有流媒体需求的java项目而言只能采用单独部署的方式并采用http及hook来进行业务交互,一定程度上增加了运维及开发的成本,所以开发或者移植一款功能齐全的流媒体服务势在必行。经过研究开发一款流媒体服务确实不太现实,正好开源流媒体服务框架ZLMediaKit提供二次开发SDK,所以我们采用ZLMediaKit C Api使用JNA技术翻译成Java Api。
总共分为三步,第一步编译并构建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中。
上面就是全部移植流程,有问题可以wx联系我:L746101210 一起研究。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。