当前位置:   article > 正文

Java实现集成流媒体服务_java流媒体服务器

java流媒体服务器

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);


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797
  • 798
  • 799
  • 800
  • 801
  • 802
  • 803
  • 804
  • 805
  • 806
  • 807
  • 808
  • 809
  • 810
  • 811
  • 812
  • 813
  • 814
  • 815
  • 816
  • 817
  • 818
  • 819
  • 820
  • 821
  • 822
  • 823
  • 824
  • 825
  • 826
  • 827
  • 828
  • 829
  • 830
  • 831
  • 832
  • 833
  • 834
  • 835
  • 836
  • 837
  • 838
  • 839
  • 840
  • 841
  • 842
  • 843
  • 844
  • 845
  • 846
  • 847
  • 848
  • 849
  • 850
  • 851
  • 852
  • 853
  • 854
  • 855
  • 856
  • 857
  • 858
  • 859
  • 860
  • 861
  • 862
  • 863
  • 864
  • 865
  • 866
  • 867
  • 868
  • 869
  • 870
  • 871
  • 872
  • 873
  • 874
  • 875
  • 876
  • 877
  • 878
  • 879
  • 880
  • 881
  • 882
  • 883
  • 884
  • 885
  • 886
  • 887
  • 888
  • 889
  • 890
  • 891
  • 892
  • 893
  • 894
  • 895
  • 896
  • 897
  • 898
  • 899
  • 900
  • 901
  • 902
  • 903
  • 904
  • 905
  • 906
  • 907
  • 908
  • 909
  • 910
  • 911
  • 912
  • 913
  • 914
  • 915
  • 916
  • 917
  • 918
  • 919
  • 920
  • 921
  • 922
  • 923
  • 924
  • 925
  • 926
  • 927
  • 928
  • 929
  • 930
  • 931
  • 932
  • 933
  • 934
  • 935
  • 936
  • 937
  • 938
  • 939
  • 940
  • 941
  • 942
  • 943
  • 944
  • 945
  • 946
  • 947
  • 948
  • 949
  • 950
  • 951
  • 952
  • 953
  • 954
  • 955
  • 956
  • 957
  • 958
  • 959
  • 960
  • 961
  • 962
  • 963
  • 964
  • 965
  • 966
  • 967
  • 968
  • 969
  • 970
  • 971
  • 972
  • 973
  • 974
  • 975
  • 976
  • 977
  • 978
  • 979
  • 980
  • 981
  • 982
  • 983
  • 984
  • 985
  • 986
  • 987
  • 988
  • 989
  • 990
  • 991
  • 992
  • 993
  • 994
  • 995
  • 996
  • 997
  • 998
  • 999
  • 1000
  • 1001
  • 1002
  • 1003
  • 1004
  • 1005
  • 1006
  • 1007
  • 1008
  • 1009
  • 1010
  • 1011
  • 1012
  • 1013
  • 1014
  • 1015
  • 1016
  • 1017
  • 1018
  • 1019
  • 1020
  • 1021
  • 1022
  • 1023
  • 1024
  • 1025
  • 1026
  • 1027
  • 1028
  • 1029
  • 1030
  • 1031
  • 1032
  • 1033
  • 1034
  • 1035
  • 1036
  • 1037
  • 1038
  • 1039
  • 1040
  • 1041
  • 1042
  • 1043
  • 1044
  • 1045
  • 1046
  • 1047
  • 1048
  • 1049
  • 1050
  • 1051
  • 1052
  • 1053
  • 1054
  • 1055
  • 1056
  • 1057
  • 1058
  • 1059
  • 1060
  • 1061
  • 1062
  • 1063
  • 1064
  • 1065
  • 1066
  • 1067
  • 1068
  • 1069
  • 1070
  • 1071
  • 1072
  • 1073
  • 1074
  • 1075
  • 1076
  • 1077
  • 1078
  • 1079
  • 1080
  • 1081
  • 1082
  • 1083
  • 1084
  • 1085
  • 1086
  • 1087
  • 1088
  • 1089
  • 1090
  • 1091
  • 1092
  • 1093
  • 1094
  • 1095
  • 1096
  • 1097
  • 1098
  • 1099
  • 1100
  • 1101
  • 1102
  • 1103
  • 1104
  • 1105
  • 1106
  • 1107
  • 1108
  • 1109
  • 1110
  • 1111
  • 1112
  • 1113
  • 1114
  • 1115
  • 1116
  • 1117
  • 1118
  • 1119
  • 1120
  • 1121
  • 1122
  • 1123
  • 1124
  • 1125
  • 1126
  • 1127
  • 1128
  • 1129
  • 1130
  • 1131
  • 1132
  • 1133
  • 1134
  • 1135
  • 1136
  • 1137
  • 1138
  • 1139
  • 1140
  • 1141
  • 1142
  • 1143
  • 1144
  • 1145
  • 1146
  • 1147
  • 1148
  • 1149
  • 1150
  • 1151
  • 1152
  • 1153
  • 1154
  • 1155
  • 1156
  • 1157
  • 1158
  • 1159
  • 1160
  • 1161
  • 1162
  • 1163
  • 1164
  • 1165
  • 1166
  • 1167
  • 1168
  • 1169
  • 1170
  • 1171
  • 1172
  • 1173
  • 1174
  • 1175
  • 1176
  • 1177
  • 1178
  • 1179
  • 1180
  • 1181
  • 1182
  • 1183
  • 1184
  • 1185
  • 1186
  • 1187
  • 1188
  • 1189
  • 1190
  • 1191
  • 1192
  • 1193
  • 1194
  • 1195
  • 1196
  • 1197
  • 1198
  • 1199
  • 1200
  • 1201
  • 1202
  • 1203
  • 1204
  • 1205
  • 1206
  • 1207
  • 1208
  • 1209
  • 1210
  • 1211
  • 1212
  • 1213
  • 1214
  • 1215
  • 1216
  • 1217
  • 1218
  • 1219
  • 1220
  • 1221
  • 1222
  • 1223
  • 1224
  • 1225
  • 1226
  • 1227
  • 1228
  • 1229
  • 1230
  • 1231
  • 1232
  • 1233
  • 1234
  • 1235
  • 1236
  • 1237
  • 1238
  • 1239
  • 1240
  • 1241
  • 1242
  • 1243
  • 1244
  • 1245
  • 1246
  • 1247
  • 1248
  • 1249
  • 1250
  • 1251
  • 1252
  • 1253
  • 1254
  • 1255
  • 1256
  • 1257
  • 1258
  • 1259
  • 1260
  • 1261
  • 1262
  • 1263
  • 1264
  • 1265
  • 1266
  • 1267
  • 1268
  • 1269
  • 1270
  • 1271
  • 1272
  • 1273
  • 1274
  • 1275
  • 1276
  • 1277
  • 1278
  • 1279
  • 1280
  • 1281
  • 1282
  • 1283
  • 1284
  • 1285
  • 1286
  • 1287
  • 1288
  • 1289
  • 1290
  • 1291
  • 1292
  • 1293
  • 1294
  • 1295
  • 1296
  • 1297
  • 1298
  • 1299
  • 1300
  • 1301
  • 1302
  • 1303
  • 1304
  • 1305
  • 1306
  • 1307
  • 1308
  • 1309
  • 1310
  • 1311
  • 1312
  • 1313
  • 1314
  • 1315
  • 1316
  • 1317
  • 1318
  • 1319
  • 1320
  • 1321
  • 1322
  • 1323
  • 1324
  • 1325
  • 1326
  • 1327
  • 1328
  • 1329
  • 1330
  • 1331
  • 1332
  • 1333
  • 1334
  • 1335
  • 1336
  • 1337
  • 1338
  • 1339
  • 1340
  • 1341
  • 1342
  • 1343
  • 1344
  • 1345
  • 1346
  • 1347
  • 1348
  • 1349
  • 1350
  • 1351
  • 1352
  • 1353
  • 1354
  • 1355
  • 1356
  • 1357
  • 1358
  • 1359
  • 1360
  • 1361
  • 1362
  • 1363
  • 1364
  • 1365
  • 1366
  • 1367
  • 1368
  • 1369
  • 1370
  • 1371
  • 1372
  • 1373
  • 1374
  • 1375
  • 1376
  • 1377
  • 1378
  • 1379
  • 1380
  • 1381
  • 1382
  • 1383
  • 1384
  • 1385
  • 1386
  • 1387
  • 1388
  • 1389
  • 1390
  • 1391
  • 1392
  • 1393
  • 1394
  • 1395
  • 1396
  • 1397
  • 1398
  • 1399
  • 1400
  • 1401
  • 1402
  • 1403
  • 1404
  • 1405
  • 1406
  • 1407
  • 1408
  • 1409
  • 1410
  • 1411
  • 1412
  • 1413

使用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();
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

还有其他回调及结构体代码就不一一放出,放在项目j_zlm_sdk 中,并基于j_zlm_sdk用SpringBoot构建了一个java版本的ZLMediaKit项目代码参见 j_media_server,此项目可作为二次开发参考。j_zlm_sdk项目已被ZLMediaKit收录到wiki中。

3.小结

上面就是全部移植流程,有问题可以wx联系我:L746101210 一起研究。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/228229
推荐阅读
相关标签
  

闽ICP备14008679号