mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 12:11:36 +08:00
全面更新整理c sdk
This commit is contained in:
parent
9736badcea
commit
cb0e5c6c57
@ -14,21 +14,18 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# ifndef MediaKitApi_STATIC
|
||||
# if defined(MediaKitApi_EXPORTS)
|
||||
# define API_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define API_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
|
||||
# define API_CALL __cdecl
|
||||
# else
|
||||
# define API_EXPORT
|
||||
# define API_CALL
|
||||
# endif
|
||||
|
||||
#else
|
||||
# define API_EXPORT
|
||||
# define API_CALL
|
||||
|
123
api/include/mk_frame.h
Normal file
123
api/include/mk_frame.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_MK_FRAME_H
|
||||
#define ZLMEDIAKIT_MK_FRAME_H
|
||||
|
||||
#include "mk_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//是否为关键帧
|
||||
#define MK_FRAME_FLAG_IS_KEY (1 << 0)
|
||||
//是否为配置帧(sps/pps/vps等)
|
||||
#define MK_FRAME_FLAG_IS_CONFIG (1 << 1)
|
||||
//是否可丢弃的帧(sei/aud)
|
||||
#define MK_FRAME_FLAG_DROP_ABLE (1 << 2)
|
||||
//是否不可单独解码的帧(多slice的非vcl帧)
|
||||
#define MK_FRAME_FLAG_NOT_DECODE_ABLE (1 << 3)
|
||||
|
||||
//codec id常量定义
|
||||
API_EXPORT extern const int MKCodecH264;
|
||||
API_EXPORT extern const int MKCodecH265;
|
||||
API_EXPORT extern const int MKCodecAAC;
|
||||
API_EXPORT extern const int MKCodecG711A;
|
||||
API_EXPORT extern const int MKCodecG711U;
|
||||
API_EXPORT extern const int MKCodecOpus;
|
||||
API_EXPORT extern const int MKCodecL16;
|
||||
API_EXPORT extern const int MKCodecVP8;
|
||||
API_EXPORT extern const int MKCodecVP9;
|
||||
API_EXPORT extern const int MKCodecAV1;
|
||||
API_EXPORT extern const int MKCodecJPEG;
|
||||
|
||||
typedef void *mk_frame;
|
||||
|
||||
// 用户自定义free回调函数
|
||||
typedef void(API_CALL *on_mk_frame_data_release)(void *user_data, char *ptr);
|
||||
|
||||
/**
|
||||
* 创建frame对象,并返回其引用
|
||||
* @param codec_id 编解码类型,请参考MKCodecXXX定义
|
||||
* @param dts 解码时间戳,单位毫秒
|
||||
* @param pts 显示时间戳,单位毫秒
|
||||
* @param data 单帧数据
|
||||
* @param size 单帧数据长度
|
||||
* @param cb data指针free释放回调, 如果为空,内部会拷贝数据
|
||||
* @param user_data data指针free释放回调用户指针
|
||||
* @return frame对象引用
|
||||
*/
|
||||
API_EXPORT mk_frame API_CALL mk_frame_create(int codec_id, uint32_t dts, uint32_t pts, const char *data, size_t size,
|
||||
on_mk_frame_data_release cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 减引用frame对象
|
||||
* @param frame 帧对象引用
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_unref(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 引用frame对象
|
||||
* @param frame 被引用的frame对象
|
||||
* @return 新的对象引用
|
||||
*/
|
||||
API_EXPORT mk_frame API_CALL mk_frame_ref(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取frame 编码codec类型,请参考MKCodecXXX定义
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_frame_codec_id(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧编码codec名称
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_frame_codec_name(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 帧是否为视频
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_frame_is_video(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧数据指针
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_frame_get_data(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧数据指针长度
|
||||
*/
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_size(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 返回帧数据前缀长度,譬如H264/H265前缀一般是0x00 00 00 01,那么本函数返回4
|
||||
*/
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_prefix_size(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取解码时间戳,单位毫秒
|
||||
*/
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_dts(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取显示时间戳,单位毫秒
|
||||
*/
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_pts(mk_frame frame);
|
||||
|
||||
/**
|
||||
* 获取帧flag,请参考 MK_FRAME_FLAG
|
||||
*/
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_flags(mk_frame frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //ZLMEDIAKIT_MK_FRAME_H
|
@ -12,6 +12,8 @@
|
||||
#define MK_MEDIA_H_
|
||||
|
||||
#include "mk_common.h"
|
||||
#include "mk_track.h"
|
||||
#include "mk_frame.h"
|
||||
#include "mk_events_objects.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -40,18 +42,29 @@ API_EXPORT mk_media API_CALL mk_media_create(const char *vhost, const char *app,
|
||||
API_EXPORT void API_CALL mk_media_release(mk_media ctx);
|
||||
|
||||
/**
|
||||
* 添加视频轨道
|
||||
* 添加音视频track
|
||||
* @param ctx mk_media对象
|
||||
* @param track mk_track对象,音视频轨道
|
||||
*/
|
||||
API_EXPORT void API_CALL 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失败
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int width, int height, float fps);
|
||||
API_EXPORT int API_CALL 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 channel 通道数
|
||||
@ -70,7 +83,15 @@ API_EXPORT int API_CALL mk_media_init_audio(mk_media ctx, int codec_id, int samp
|
||||
API_EXPORT void API_CALL mk_media_init_complete(mk_media ctx);
|
||||
|
||||
/**
|
||||
* 输入单帧H264视频,帧起始字节00 00 01,00 00 00 01均可
|
||||
* 输入frame对象
|
||||
* @param ctx mk_media对象
|
||||
* @param frame 帧对象
|
||||
* @return 1代表成功,0失败
|
||||
*/
|
||||
API_EXPORT int API_CALL 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数据字节数
|
||||
@ -81,7 +102,7 @@ API_EXPORT void API_CALL mk_media_init_complete(mk_media ctx);
|
||||
API_EXPORT int API_CALL mk_media_input_h264(mk_media ctx, const void *data, int len, uint32_t dts, uint32_t pts);
|
||||
|
||||
/**
|
||||
* 输入单帧H265视频,帧起始字节00 00 01,00 00 00 01均可
|
||||
* 输入单帧H265视频,帧起始字节00 00 01,00 00 00 01均可,请改用mk_media_input_frame方法
|
||||
* @param ctx 对象指针
|
||||
* @param data 单帧H265数据
|
||||
* @param len 单帧H265数据字节数
|
||||
@ -92,7 +113,16 @@ API_EXPORT int API_CALL mk_media_input_h264(mk_media ctx, const void *data, int
|
||||
API_EXPORT int API_CALL mk_media_input_h265(mk_media ctx, const void *data, int len, uint32_t dts, uint32_t pts);
|
||||
|
||||
/**
|
||||
* 输入单帧AAC音频(单独指定adts头)
|
||||
* 输入YUV视频数据
|
||||
* @param ctx 对象指针
|
||||
* @param yuv yuv420p数据
|
||||
* @param linesize yuv420p linesize
|
||||
* @param cts 视频采集时间戳,单位毫秒
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_media_input_yuv(mk_media ctx, const char *yuv[3], int linesize[3], uint32_t cts);
|
||||
|
||||
/**
|
||||
* 输入单帧AAC音频(单独指定adts头),请改用mk_media_input_frame方法
|
||||
* @param ctx 对象指针
|
||||
* @param data 不包含adts头的单帧AAC数据,adts头7个字节
|
||||
* @param len 单帧AAC数据字节数
|
||||
@ -113,7 +143,7 @@ API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int l
|
||||
API_EXPORT int API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, uint32_t pts);
|
||||
|
||||
/**
|
||||
* 输入单帧OPUS/G711音频帧
|
||||
* 输入单帧OPUS/G711音频帧,请改用mk_media_input_frame方法
|
||||
* @param ctx 对象指针
|
||||
* @param data 单帧音频数据
|
||||
* @param len 单帧音频数据字节数
|
||||
|
@ -24,5 +24,8 @@
|
||||
#include "mk_thread.h"
|
||||
#include "mk_rtp_server.h"
|
||||
#include "mk_h264_splitter.h"
|
||||
#include "mk_frame.h"
|
||||
#include "mk_track.h"
|
||||
#include "mk_transcode.h"
|
||||
|
||||
#endif /* MK_API_H_ */
|
||||
|
@ -12,6 +12,8 @@
|
||||
#define MK_PLAYER_H_
|
||||
|
||||
#include "mk_common.h"
|
||||
#include "mk_frame.h"
|
||||
#include "mk_track.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -24,20 +26,11 @@ typedef void* mk_player;
|
||||
* @param user_data 用户数据指针
|
||||
* @param err_code 错误代码,0为成功
|
||||
* @param err_msg 错误提示
|
||||
* @param tracks track列表
|
||||
* @param track_count track个数
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_play_event)(void *user_data,int err_code,const char *err_msg);
|
||||
|
||||
/**
|
||||
* 收到音视频数据回调
|
||||
* @param user_data 用户数据指针
|
||||
* @param track_type 0:视频,1:音频
|
||||
* @param codec_id 0:H264,1:H265,2:AAC 3.G711A 4.G711U 5.OPUS
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* @param dts 解码时间戳,单位毫秒
|
||||
* @param pts 显示时间戳,单位毫秒
|
||||
*/
|
||||
typedef void(API_CALL *on_mk_play_data)(void *user_data,int track_type,int codec_id,void *data,size_t len, uint32_t dts,uint32_t pts);
|
||||
typedef void(API_CALL *on_mk_play_event)(void *user_data, int err_code, const char *err_msg, mk_track tracks[],
|
||||
int track_count);
|
||||
|
||||
/**
|
||||
* 创建一个播放器,支持rtmp[s]/rtsp[s]
|
||||
@ -54,7 +47,7 @@ API_EXPORT void API_CALL mk_player_release(mk_player ctx);
|
||||
/**
|
||||
* 设置播放器配置选项
|
||||
* @param ctx 播放器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/max_analysis_ms
|
||||
* @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
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_option(mk_player ctx, const char *key, const char *val);
|
||||
@ -110,67 +103,8 @@ API_EXPORT void API_CALL mk_player_set_on_result(mk_player ctx, on_mk_play_event
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_event cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 设置音视频数据回调函数
|
||||
* @param ctx 播放器指针
|
||||
* @param cb 回调函数指针,设置null立即取消回调
|
||||
* @param user_data 用户数据指针
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data);
|
||||
|
||||
///////////////////////////获取音视频相关信息接口在播放成功回调触发后才有效///////////////////////////////
|
||||
|
||||
/**
|
||||
* 获取视频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U
|
||||
* @param ctx 播放器指针
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_video_codec_id(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取视频codec_id, vendor类型, 私有头数据 codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U
|
||||
* @param ctx 播放器指针
|
||||
* @param vendor 输出厂家类型 如果是私有流 应该是H264另外还有厂家类型
|
||||
* @param head 厂家SDK头数据
|
||||
* @param head 厂家SDK头数据长度
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_video_codec_id_vendor_head(mk_player ctx, char* vendor, char* head, int* headLen);
|
||||
|
||||
/**
|
||||
* 获取视频宽度
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_video_width(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取视频高度
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_video_height(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取视频帧率
|
||||
*/
|
||||
API_EXPORT float API_CALL mk_player_video_fps(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取音频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U
|
||||
* @param ctx 播放器指针
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_audio_codec_id(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取音频采样率
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取音频采样位数,一般为16
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取音频通道数
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx);
|
||||
|
||||
/**
|
||||
* 获取点播节目时长,如果是直播返回0,否则返回秒数
|
||||
*/
|
||||
@ -193,7 +127,6 @@ API_EXPORT int API_CALL mk_player_progress_pos(mk_player ctx);
|
||||
*/
|
||||
API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -40,7 +40,7 @@ API_EXPORT void API_CALL mk_proxy_player_release(mk_proxy_player ctx);
|
||||
/**
|
||||
* 设置代理播放器配置选项
|
||||
* @param ctx 代理播放器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/max_analysis_ms
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
|
||||
* @param val 配置项值,如果是整形,需要转换成统一转换成string
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_proxy_player_set_option(mk_proxy_player ctx, const char *key, const char *val);
|
||||
|
@ -60,7 +60,7 @@ API_EXPORT void API_CALL mk_pusher_release(mk_pusher ctx);
|
||||
/**
|
||||
* 设置推流器配置选项
|
||||
* @param ctx 推流器指针
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/max_analysis_ms
|
||||
* @param key 配置项键,支持 net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
|
||||
* @param val 配置项值,如果是整形,需要转换成统一转换成string
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_pusher_set_option(mk_pusher ctx, const char *key, const char *val);
|
||||
|
@ -17,6 +17,25 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////Buffer::Ptr/////////////////////////////////////////////
|
||||
|
||||
typedef void *mk_buffer;
|
||||
typedef void(API_CALL *on_mk_buffer_free)(void *user_data, void *data);
|
||||
|
||||
/**
|
||||
* 创建buffer对象
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* @param cb 数据指针free回调函数,该参数置空时,内部会拷贝数据
|
||||
* @param user_data 数据指针free回调函数on_mk_buffer_free第一个参数
|
||||
* @return buffer对象
|
||||
*/
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_from_char(const char *data, size_t len, on_mk_buffer_free cb, void *user_data);
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_ref(mk_buffer buffer);
|
||||
API_EXPORT void API_CALL mk_buffer_unref(mk_buffer buffer);
|
||||
API_EXPORT const char* API_CALL mk_buffer_get_data(mk_buffer buffer);
|
||||
API_EXPORT size_t API_CALL mk_buffer_get_size(mk_buffer buffer);
|
||||
|
||||
///////////////////////////////////////////SockInfo/////////////////////////////////////////////
|
||||
//SockInfo对象的C映射
|
||||
typedef void* mk_sock_info;
|
||||
@ -47,6 +66,8 @@ API_EXPORT uint16_t API_CALL mk_sock_info_local_port(const mk_sock_info ctx);
|
||||
///////////////////////////////////////////TcpSession/////////////////////////////////////////////
|
||||
//TcpSession对象的C映射
|
||||
typedef void* mk_tcp_session;
|
||||
typedef void* mk_tcp_session_ref;
|
||||
|
||||
//获取基类指针以便获取其网络相关信息
|
||||
API_EXPORT mk_sock_info API_CALL mk_tcp_session_get_sock_info(const mk_tcp_session ctx);
|
||||
|
||||
@ -54,8 +75,18 @@ API_EXPORT mk_sock_info API_CALL mk_tcp_session_get_sock_info(const mk_tcp_sessi
|
||||
API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int err,const char *err_msg);
|
||||
//TcpSession::send()
|
||||
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx, const char *data, size_t len);
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer(const mk_tcp_session ctx, mk_buffer buffer);
|
||||
|
||||
//切换到该对象所在线程后再TcpSession::send()
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx, const char *data, size_t len);
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer_safe(const mk_tcp_session ctx, mk_buffer buffer);
|
||||
|
||||
//创建mk_tcp_session的弱引用
|
||||
API_EXPORT mk_tcp_session_ref API_CALL mk_tcp_session_ref_from(const mk_tcp_session ctx);
|
||||
//删除mk_tcp_session的弱引用
|
||||
API_EXPORT void mk_tcp_session_ref_release(const mk_tcp_session_ref ref);
|
||||
//根据弱引用获取mk_tcp_session,如果mk_tcp_session已经销毁,那么返回NULL
|
||||
API_EXPORT mk_tcp_session mk_tcp_session_from_ref(const mk_tcp_session_ref ref);
|
||||
|
||||
///////////////////////////////////////////自定义tcp服务/////////////////////////////////////////////
|
||||
|
||||
@ -71,10 +102,9 @@ typedef struct {
|
||||
* 收到客户端发过来的数据
|
||||
* @param server_port 服务器端口号
|
||||
* @param session 会话处理对象
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* @param buffer 数据
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_session_data)(uint16_t server_port,mk_tcp_session session,const char *data,size_t len);
|
||||
void (API_CALL *on_mk_tcp_session_data)(uint16_t server_port,mk_tcp_session session, mk_buffer buffer);
|
||||
|
||||
/**
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
@ -161,10 +191,9 @@ typedef struct {
|
||||
/**
|
||||
* 收到tcp服务器发来的数据
|
||||
* @param client tcp客户端
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
* @param buffer 数据
|
||||
*/
|
||||
void (API_CALL *on_mk_tcp_client_data)(mk_tcp_client client,const char *data,size_t len);
|
||||
void (API_CALL *on_mk_tcp_client_data)(mk_tcp_client client, mk_buffer buffer);
|
||||
|
||||
/**
|
||||
* 每隔2秒的定时器,用于管理超时等任务
|
||||
@ -205,6 +234,7 @@ API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *ho
|
||||
* @param len 数据长度,等于0时,内部通过strlen获取
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len);
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer(mk_tcp_client ctx, mk_buffer buffer);
|
||||
|
||||
/**
|
||||
* 切换到本对象的网络线程后再发送数据
|
||||
@ -213,6 +243,7 @@ API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data,
|
||||
* @param len 数据长度,等于0时,内部通过strlen获取
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_safe(mk_tcp_client ctx, const char *data, int len);
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer_safe(mk_tcp_client ctx, mk_buffer buffer);
|
||||
|
||||
/**
|
||||
* 客户端附着用户数据
|
||||
|
@ -52,6 +52,31 @@ API_EXPORT mk_thread API_CALL mk_thread_from_pool();
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_pool_work();
|
||||
|
||||
typedef void* mk_thread_pool;
|
||||
|
||||
/**
|
||||
* 创建线程池
|
||||
* @param name 线程池名称,方便调试
|
||||
* @param n_thread 线程个数,0时为cpu个数
|
||||
* @param priority 线程优先级,分为PRIORITY_LOWEST = 0,PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_HIGHEST
|
||||
* @return 线程池
|
||||
*/
|
||||
API_EXPORT mk_thread_pool API_CALL mk_thread_pool_create(const char *name, size_t n_thread, int priority);
|
||||
|
||||
/**
|
||||
* 销毁线程池
|
||||
* @param pool 线程池
|
||||
* @return 0:成功
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_thread_pool_release(mk_thread_pool pool);
|
||||
|
||||
/**
|
||||
* 从线程池获取一个线程
|
||||
* @param pool 线程池
|
||||
* @return 线程
|
||||
*/
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_thread_pool(mk_thread_pool pool);
|
||||
|
||||
///////////////////////////////////////////线程切换/////////////////////////////////////////////
|
||||
typedef void (API_CALL *on_mk_async)(void *user_data);
|
||||
|
||||
@ -63,6 +88,15 @@ typedef void (API_CALL *on_mk_async)(void *user_data);
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_async_do(mk_thread ctx, on_mk_async cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 切换到事件线程并延时执行
|
||||
* @param ctx 事件线程
|
||||
* @param ms 延时时间,单位毫秒
|
||||
* @param cb 回调函数
|
||||
* @param user_data 用户数据指针
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_async_do_delay(mk_thread ctx, size_t ms, on_mk_async cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 切换到事件线程并同步执行
|
||||
* @param ctx 事件线程
|
||||
@ -96,6 +130,31 @@ API_EXPORT mk_timer API_CALL mk_timer_create(mk_thread ctx,uint64_t delay_ms, on
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_timer_release(mk_timer ctx);
|
||||
|
||||
///////////////////////////////////////////信号量/////////////////////////////////////////////
|
||||
|
||||
typedef void* mk_sem;
|
||||
|
||||
/**
|
||||
* 创建信号量
|
||||
*/
|
||||
API_EXPORT mk_sem API_CALL mk_sem_create();
|
||||
|
||||
/**
|
||||
* 销毁信号量
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_release(mk_sem sem);
|
||||
|
||||
/**
|
||||
* 信号量加n
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_post(mk_sem sem, size_t n);
|
||||
|
||||
/**
|
||||
* 信号量减1
|
||||
* @param sem
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_sem_wait(mk_sem sem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
135
api/include/mk_track.h
Normal file
135
api/include/mk_track.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_MK_TRACK_H
|
||||
#define ZLMEDIAKIT_MK_TRACK_H
|
||||
|
||||
#include "mk_common.h"
|
||||
#include "mk_frame.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//音视频轨道
|
||||
typedef void* mk_track;
|
||||
//输出frame回调
|
||||
typedef void(API_CALL *on_mk_frame_out)(void *user_data, mk_frame frame);
|
||||
|
||||
//track创建参数
|
||||
typedef union {
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
int fps;
|
||||
} video;
|
||||
|
||||
struct {
|
||||
int channels;
|
||||
int sample_rate;
|
||||
} audio;
|
||||
} codec_args;
|
||||
|
||||
/**
|
||||
* 创建track对象引用
|
||||
* @param codec_id 请参考MKCodecXXX 常量定义
|
||||
* @param args 视频或音频参数
|
||||
* @return track对象引用
|
||||
*/
|
||||
API_EXPORT mk_track API_CALL mk_track_create(int codec_id, codec_args *args);
|
||||
|
||||
/**
|
||||
* 减引用track对象
|
||||
* @param track track对象
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_unref(mk_track track);
|
||||
|
||||
/**
|
||||
* 引用track对象
|
||||
* @param track track对象
|
||||
* @return 新的track引用对象
|
||||
*/
|
||||
API_EXPORT mk_track API_CALL mk_track_ref(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取track 编码codec类型,请参考MKCodecXXX定义
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_codec_id(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取编码codec名称
|
||||
*/
|
||||
API_EXPORT const char* API_CALL mk_track_codec_name(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取比特率信息
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_bit_rate(mk_track track);
|
||||
|
||||
/**
|
||||
* 监听frame输出事件
|
||||
* @param track track对象
|
||||
* @param cb frame输出回调
|
||||
* @param user_data frame输出回调用户指针参数
|
||||
*/
|
||||
API_EXPORT void *API_CALL mk_track_add_delegate(mk_track track, on_mk_frame_out cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 取消frame输出事件监听
|
||||
* @param track track对象
|
||||
* @param tag mk_track_add_delegate返回值
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_del_delegate(mk_track track, void *tag);
|
||||
|
||||
/**
|
||||
* 输入frame到track,通常你不需要调用此api
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_track_input_frame(mk_track track, mk_frame frame);
|
||||
|
||||
/**
|
||||
* track是否为视频
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_is_video(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频宽度
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_width(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频高度
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_height(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取视频帧率
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_video_fps(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频采样率
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_rate(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频通道数
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_channel(mk_track track);
|
||||
|
||||
/**
|
||||
* 获取音频位数,一般为16bit
|
||||
*/
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_bit(mk_track track);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //ZLMEDIAKIT_MK_TRACK_H
|
154
api/include/mk_transcode.h
Normal file
154
api/include/mk_transcode.h
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ZLMEDIAKIT_MK_TRANSCODE_H
|
||||
#define ZLMEDIAKIT_MK_TRANSCODE_H
|
||||
|
||||
#include "mk_common.h"
|
||||
#include "mk_track.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//解码器对象
|
||||
typedef void *mk_decoder;
|
||||
//解码后的frame
|
||||
typedef void *mk_frame_pix;
|
||||
//SwsContext的包装
|
||||
typedef void *mk_swscale;
|
||||
//FFmpeg原始解码帧对象
|
||||
typedef struct AVFrame AVFrame;
|
||||
//FFmpeg编解码器对象
|
||||
typedef struct AVCodecContext AVCodecContext;
|
||||
//解码输出回调
|
||||
typedef void(API_CALL *on_mk_decode)(void *user_data, mk_frame_pix frame);
|
||||
|
||||
/**
|
||||
* 创建解码器
|
||||
* @param track track对象
|
||||
* @param thread_num 解码线程数,0时为自动
|
||||
* @return 返回解码器对象,NULL代表失败
|
||||
*/
|
||||
API_EXPORT mk_decoder API_CALL mk_decoder_create(mk_track track, int thread_num);
|
||||
|
||||
/**
|
||||
* 销毁解码器
|
||||
* @param ctx 解码器对象
|
||||
* @param flush_frame 是否等待所有帧解码成功
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_release(mk_decoder ctx, int flush_frame);
|
||||
|
||||
/**
|
||||
* 解码音视频帧
|
||||
* @param ctx 解码器
|
||||
* @param frame 帧对象
|
||||
* @param async 是否异步解码
|
||||
* @param enable_merge 是否合并帧解码,有些情况下,需要把时间戳相同的slice合并输入到解码器才能解码
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_decode(mk_decoder ctx, mk_frame frame, int async, int enable_merge);
|
||||
|
||||
/**
|
||||
* 设置异步解码最大帧缓存积压数限制
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_set_max_async_frame_size(mk_decoder ctx, size_t size);
|
||||
|
||||
/**
|
||||
* 设置解码输出回调
|
||||
* @param ctx 解码器
|
||||
* @param cb 回调函数
|
||||
* @param user_data 回调函数用户指针参数
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_decoder_set_cb(mk_decoder ctx, on_mk_decode cb, void *user_data);
|
||||
|
||||
/**
|
||||
* 获取FFmpeg原始AVCodecContext对象
|
||||
* @param ctx 解码器
|
||||
*/
|
||||
API_EXPORT const AVCodecContext* API_CALL mk_decoder_get_context(mk_decoder ctx);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 创建解码帧mk_frame_pix新引用
|
||||
* @param frame 原始引用
|
||||
* @return 新引用
|
||||
*/
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_ref(mk_frame_pix frame);
|
||||
|
||||
/**
|
||||
* 解码帧mk_frame_pix减引用
|
||||
* @param frame 原始引用
|
||||
*/
|
||||
API_EXPORT void API_CALL mk_frame_pix_unref(mk_frame_pix frame);
|
||||
|
||||
/**
|
||||
* 从FFmpeg AVFrame转换为mk_frame_pix
|
||||
* @param frame FFmpeg AVFrame
|
||||
* @return mk_frame_pix对象
|
||||
*/
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_av_frame(AVFrame *frame);
|
||||
|
||||
/**
|
||||
* 获取FFmpeg AVFrame对象
|
||||
* @param frame 解码帧mk_frame_pix
|
||||
* @return FFmpeg AVFrame对象
|
||||
*/
|
||||
API_EXPORT AVFrame* API_CALL mk_frame_pix_get_av_frame(mk_frame_pix frame);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 创建ffmpeg SwsContext wrapper实例
|
||||
* @param output AVPixelFormat类型,AV_PIX_FMT_BGR24==3
|
||||
* @param width 目标宽度,置0时,则与输入时一致
|
||||
* @param height 目标高度,置0时,则与输入时一致
|
||||
* @return SwsContext wrapper 实例
|
||||
*/
|
||||
API_EXPORT mk_swscale mk_swscale_create(int output, int width, int height);
|
||||
|
||||
/**
|
||||
* 释放ffmpeg SwsContext wrapper实例
|
||||
* @param ctx SwsContext wrapper实例
|
||||
*/
|
||||
API_EXPORT void mk_swscale_release(mk_swscale ctx);
|
||||
|
||||
/**
|
||||
* 使用SwsContext转换pix format
|
||||
* @param ctx SwsContext wrapper实例
|
||||
* @param frame pix frame
|
||||
* @param out 转换后存放的数据指针,用户需要确保提前申请并大小足够
|
||||
* @return sws_scale()返回值:the height of the output slice
|
||||
*/
|
||||
API_EXPORT int mk_swscale_input_frame(mk_swscale ctx, mk_frame_pix frame, uint8_t *out);
|
||||
|
||||
/**
|
||||
* 使用SwsContext转换pix format
|
||||
* @param ctx SwsContext wrapper实例
|
||||
* @param frame pix frame
|
||||
* @return 新的pix frame对象,需要使用mk_frame_pix_unref销毁
|
||||
*/
|
||||
API_EXPORT mk_frame_pix mk_swscale_input_frame2(mk_swscale ctx, mk_frame_pix frame);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
API_EXPORT uint8_t** API_CALL mk_get_av_frame_data(AVFrame *frame);
|
||||
API_EXPORT int* API_CALL mk_get_av_frame_line_size(AVFrame *frame);
|
||||
API_EXPORT int64_t API_CALL mk_get_av_frame_dts(AVFrame *frame);
|
||||
API_EXPORT int64_t API_CALL mk_get_av_frame_pts(AVFrame *frame);
|
||||
API_EXPORT int API_CALL mk_get_av_frame_width(AVFrame *frame);
|
||||
API_EXPORT int API_CALL mk_get_av_frame_height(AVFrame *frame);
|
||||
API_EXPORT int API_CALL mk_get_av_frame_format(AVFrame *frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //ZLMEDIAKIT_MK_TRANSCODE_H
|
@ -7,6 +7,7 @@
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_WEBRTC
|
||||
#ifndef MK_WEBRTC_API_H
|
||||
#define MK_WEBRTC_API_H
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "Util/logger.h"
|
||||
#include "Util/SSLBox.h"
|
||||
#include "Network/TcpServer.h"
|
||||
#include "Network/UdpServer.h"
|
||||
#include "Thread/WorkThreadPool.h"
|
||||
|
||||
#include "Rtsp/RtspSession.h"
|
||||
|
176
api/source/mk_frame.cpp
Normal file
176
api/source/mk_frame.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "mk_frame.h"
|
||||
#include "Extension/Frame.h"
|
||||
#include "Extension/H264.h"
|
||||
#include "Extension/H265.h"
|
||||
#include "Extension/AAC.h"
|
||||
|
||||
using namespace mediakit;
|
||||
|
||||
extern "C" {
|
||||
#define XX(name, type, value, str, mpeg_id) const int MK##name = value;
|
||||
CODEC_MAP(XX)
|
||||
#undef XX
|
||||
}
|
||||
|
||||
class FrameFromPtrForC : public FrameFromPtr {
|
||||
public:
|
||||
using Ptr = std::shared_ptr<FrameFromPtrForC>;
|
||||
|
||||
template<typename ...ARGS>
|
||||
FrameFromPtrForC(bool cache_able, uint32_t flags, on_mk_frame_data_release cb, void *user_data, ARGS &&...args) : FrameFromPtr(
|
||||
std::forward<ARGS>(args)...) {
|
||||
_flags = flags;
|
||||
_cb = cb;
|
||||
_user_data = user_data;
|
||||
_cache_able = cache_able;
|
||||
}
|
||||
|
||||
~FrameFromPtrForC() override {
|
||||
if (_cb) {
|
||||
_cb(_user_data, _ptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool cacheAble() const override {
|
||||
return _cache_able;
|
||||
}
|
||||
|
||||
bool keyFrame() const override {
|
||||
return _flags & MK_FRAME_FLAG_IS_KEY;
|
||||
}
|
||||
|
||||
bool configFrame() const override {
|
||||
return _flags & MK_FRAME_FLAG_IS_CONFIG;
|
||||
}
|
||||
|
||||
//默认返回false
|
||||
bool dropAble() const override {
|
||||
return _flags & MK_FRAME_FLAG_DROP_ABLE;
|
||||
}
|
||||
|
||||
//默认返回true
|
||||
bool decodeAble() const override {
|
||||
return !(_flags & MK_FRAME_FLAG_NOT_DECODE_ABLE);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t _flags;
|
||||
on_mk_frame_data_release _cb;
|
||||
void *_user_data;
|
||||
bool _cache_able;
|
||||
};
|
||||
|
||||
static mk_frame mk_frame_create_complex(int codec_id, uint32_t dts, uint32_t pts, uint32_t frame_flags, size_t prefix_size,
|
||||
char *data, size_t size, on_mk_frame_data_release cb, void *user_data) {
|
||||
switch (codec_id) {
|
||||
case CodecH264:
|
||||
return new Frame::Ptr(new H264FrameHelper<FrameFromPtrForC>(cb, frame_flags, cb, user_data, (CodecId) codec_id,
|
||||
data, size, dts, pts, prefix_size));
|
||||
case CodecH265:
|
||||
return new Frame::Ptr(new H265FrameHelper<FrameFromPtrForC>(cb, frame_flags, cb, user_data, (CodecId) codec_id,
|
||||
data, size, dts, pts, prefix_size));
|
||||
default:
|
||||
return new Frame::Ptr(new FrameFromPtrForC(cb, frame_flags, cb, user_data, (CodecId) codec_id, data,
|
||||
size, dts, pts, prefix_size));
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORT mk_frame API_CALL mk_frame_create(int codec_id, uint32_t dts, uint32_t pts, const char *data, size_t size,
|
||||
on_mk_frame_data_release cb, void *user_data) {
|
||||
|
||||
switch (codec_id) {
|
||||
case CodecH264:
|
||||
case CodecH265:
|
||||
return mk_frame_create_complex(codec_id, dts, pts, 0, prefixSize(data, size), (char *)data, size, cb, user_data);
|
||||
|
||||
case CodecAAC: {
|
||||
int prefix = 0;
|
||||
if ((((uint8_t *) data)[0] == 0xFF && (((uint8_t *) data)[1] & 0xF0) == 0xF0) && size > ADTS_HEADER_LEN) {
|
||||
prefix = ADTS_HEADER_LEN;
|
||||
}
|
||||
return mk_frame_create_complex(codec_id, dts, pts, 0, prefix, (char *)data, size, cb, user_data);
|
||||
}
|
||||
|
||||
default:
|
||||
return mk_frame_create_complex(codec_id, dts, pts, 0, 0, (char *)data, size, cb, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_frame_unref(mk_frame frame) {
|
||||
assert(frame);
|
||||
delete (Frame::Ptr *) frame;
|
||||
}
|
||||
|
||||
API_EXPORT mk_frame API_CALL mk_frame_ref(mk_frame frame) {
|
||||
assert(frame);
|
||||
return new Frame::Ptr(Frame::getCacheAbleFrame(*((Frame::Ptr *) frame)));
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_frame_codec_id(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->getCodecId();
|
||||
}
|
||||
|
||||
API_EXPORT const char *API_CALL mk_frame_codec_name(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->getCodecName();
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_frame_is_video(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->getTrackType() == TrackVideo;
|
||||
}
|
||||
|
||||
API_EXPORT const char *API_CALL mk_frame_get_data(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->data();
|
||||
}
|
||||
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_size(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->size();
|
||||
}
|
||||
|
||||
API_EXPORT size_t API_CALL mk_frame_get_data_prefix_size(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->prefixSize();
|
||||
}
|
||||
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_dts(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->dts();
|
||||
}
|
||||
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_pts(mk_frame frame) {
|
||||
assert(frame);
|
||||
return (*((Frame::Ptr *) frame))->pts();
|
||||
}
|
||||
|
||||
API_EXPORT uint32_t API_CALL mk_frame_get_flags(mk_frame frame) {
|
||||
assert(frame);
|
||||
auto &ref = *((Frame::Ptr *) frame);
|
||||
uint32_t ret = 0;
|
||||
if (ref->keyFrame()) {
|
||||
ret &= MK_FRAME_FLAG_IS_KEY;
|
||||
}
|
||||
if (ref->configFrame()) {
|
||||
ret &= MK_FRAME_FLAG_IS_CONFIG;
|
||||
}
|
||||
if (ref->dropAble()) {
|
||||
ret &= MK_FRAME_FLAG_DROP_ABLE;
|
||||
}
|
||||
if (!ref->decodeAble()) {
|
||||
ret &= MK_FRAME_FLAG_NOT_DECODE_ABLE;
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -178,7 +178,7 @@ API_EXPORT void API_CALL mk_media_release(mk_media ctx) {
|
||||
delete obj;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int width, int height, float fps){
|
||||
API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int width, int height, float fps, int bit_rate){
|
||||
assert(ctx);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
VideoInfo info;
|
||||
@ -186,6 +186,8 @@ API_EXPORT int API_CALL mk_media_init_video(mk_media ctx, int codec_id, int widt
|
||||
info.iFrameRate = fps;
|
||||
info.iWidth = width;
|
||||
info.iHeight = height;
|
||||
info.iBitRate = bit_rate;
|
||||
(*obj)->getChannel()->initVideo(info);
|
||||
return (*obj)->getChannel()->initVideo(info);
|
||||
}
|
||||
|
||||
@ -200,12 +202,24 @@ API_EXPORT int API_CALL mk_media_init_audio(mk_media ctx, int codec_id, int samp
|
||||
return (*obj)->getChannel()->initAudio(info);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_media_init_track(mk_media ctx, mk_track track){
|
||||
assert(ctx && track);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
(*obj)->getChannel()->addTrack(*((Track::Ptr *) track));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_media_init_complete(mk_media ctx){
|
||||
assert(ctx);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
(*obj)->getChannel()->addTrackCompleted();
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_input_frame(mk_media ctx, mk_frame frame){
|
||||
assert(ctx && frame);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
return (*obj)->getChannel()->inputFrame(*((Frame::Ptr *) frame));
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_input_h264(mk_media ctx, const void *data, int len, uint32_t dts, uint32_t pts) {
|
||||
assert(ctx && data && len > 0);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
@ -218,6 +232,12 @@ API_EXPORT int API_CALL mk_media_input_h265(mk_media ctx, const void *data, int
|
||||
return (*obj)->getChannel()->inputH265((const char *) data, len, dts, pts);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_media_input_yuv(mk_media ctx, const char *yuv[3], int linesize[3], uint32_t cts) {
|
||||
assert(ctx && yuv && linesize);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
(*obj)->getChannel()->inputYUV((char **) yuv, linesize, cts);
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int len, uint32_t dts, void *adts) {
|
||||
assert(ctx && data && len > 0 && adts);
|
||||
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
|
||||
|
@ -48,10 +48,12 @@ public:
|
||||
}
|
||||
|
||||
void unset() {
|
||||
for (auto &track : _player->getTracks(false)) {
|
||||
track->clear();
|
||||
}
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
_on_play = nullptr;
|
||||
_on_shutdown = nullptr;
|
||||
_on_data = nullptr;
|
||||
}
|
||||
|
||||
void onEvent(bool is_shutdown, const SockException &ex){
|
||||
@ -59,39 +61,20 @@ public:
|
||||
if (is_shutdown) {
|
||||
//播放中断
|
||||
if (_on_shutdown) {
|
||||
_on_shutdown(_on_shutdown_data,ex.getErrCode(),ex.what());
|
||||
_on_shutdown(_on_shutdown_data, ex.getErrCode(), ex.what(), nullptr, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//播放结果
|
||||
if (_on_play) {
|
||||
_on_play(_on_play_data,ex.getErrCode(),ex.what());
|
||||
auto cpp_tracks = _player->getTracks(false);
|
||||
mk_track tracks[TrackMax] = {nullptr};
|
||||
int track_count = 0;
|
||||
for (auto &track : cpp_tracks) {
|
||||
tracks[track_count++] = (mk_track) &track;
|
||||
}
|
||||
|
||||
if(ex){
|
||||
//播放失败
|
||||
return;
|
||||
}
|
||||
|
||||
//播放成功,添加事件回调
|
||||
weak_ptr<MediaPlayerForC> weak_self = shared_from_this();
|
||||
auto delegate = std::make_shared<FrameWriterInterfaceHelper>([weak_self](const Frame::Ptr &frame) {
|
||||
if (auto strong_self = weak_self.lock()) {
|
||||
strong_self->onData(frame);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
for (auto &track : _player->getTracks(false)) {
|
||||
track->addDelegate(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
void onData(const Frame::Ptr &frame){
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
if(_on_data){
|
||||
_on_data(_on_data_data,frame->getTrackType(),frame->getCodecId(),frame->data(),frame->size(),frame->dts(),frame->pts());
|
||||
_on_play(_on_play_data, ex.getErrCode(), ex.what(), tracks, track_count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,12 +89,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void setOnData(on_mk_play_data cb, void *user_data) {
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
_on_data_data = user_data;
|
||||
_on_data = cb;
|
||||
}
|
||||
|
||||
MediaPlayer::Ptr& getPlayer(){
|
||||
return _player;
|
||||
}
|
||||
@ -119,12 +96,10 @@ private:
|
||||
MediaPlayer::Ptr _player;
|
||||
recursive_mutex _mtx;
|
||||
on_mk_play_event _on_play = nullptr;
|
||||
on_mk_play_data _on_data = nullptr;
|
||||
on_mk_play_event _on_shutdown = nullptr;
|
||||
|
||||
void *_on_play_data = nullptr;
|
||||
void *_on_shutdown_data = nullptr;
|
||||
void *_on_data_data = nullptr;
|
||||
};
|
||||
|
||||
API_EXPORT mk_player API_CALL mk_player_create() {
|
||||
@ -214,90 +189,6 @@ API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_eve
|
||||
mk_player_set_on_event(ctx,cb,user_data,1);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
obj.setOnData(cb,user_data);
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_video_codec_id(mk_player ctx){
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<VideoTrack>(obj->getTrack(TrackVideo));
|
||||
return track ? track->getCodecId() : CodecInvalid;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_video_codec_id_vendor_head(mk_player ctx, char *vendor, char *head, int *head_len) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx);
|
||||
auto track = dynamic_pointer_cast<VideoTrack>(obj->getTrack(TrackVideo));
|
||||
int codecId = track ? track->getCodecId() : CodecInvalid;
|
||||
if (codecId == CodecH264) {
|
||||
auto h264Track = dynamic_pointer_cast<H264Track>(obj->getTrack(TrackVideo));
|
||||
auto pps = h264Track->getPps();
|
||||
auto ppsLen = pps.size();
|
||||
if (ppsLen >= (4 + 16)) {
|
||||
std::string temVendor = std::string(pps.c_str() + 4, 16);
|
||||
memcpy(vendor, temVendor.c_str(), temVendor.length());
|
||||
if (ppsLen > (4 + 16)) {
|
||||
std::string temHead = std::string(pps.c_str() + 20, ppsLen - 20);
|
||||
memcpy(head, temHead.c_str(), temHead.length());
|
||||
*head_len = temHead.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return codecId;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<VideoTrack>(obj->getTrack(TrackVideo));
|
||||
return track ? track->getVideoWidth() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_video_height(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<VideoTrack>(obj->getTrack(TrackVideo));
|
||||
return track ? track->getVideoHeight() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT float API_CALL mk_player_video_fps(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<VideoTrack>(obj->getTrack(TrackVideo));
|
||||
return track ? track->getVideoFps() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_audio_codec_id(mk_player ctx){
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<AudioTrack>(obj->getTrack(TrackAudio));
|
||||
return track ? track->getCodecId() : CodecInvalid;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<AudioTrack>(obj->getTrack(TrackAudio));
|
||||
return track ? track->getAudioSampleRate() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<AudioTrack>(obj->getTrack(TrackAudio));
|
||||
return track ? track->getAudioSampleBit() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
auto track = dynamic_pointer_cast<AudioTrack>(obj->getTrack(TrackAudio));
|
||||
return track ? track->getAudioChannel() : 0;
|
||||
}
|
||||
|
||||
API_EXPORT float API_CALL mk_player_duration(mk_player ctx) {
|
||||
assert(ctx);
|
||||
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
|
||||
|
@ -13,10 +13,76 @@
|
||||
#include "mk_tcp_private.h"
|
||||
#include "Http/WebSocketClient.h"
|
||||
#include "Http/WebSocketSession.h"
|
||||
#include "Network/Buffer.h"
|
||||
|
||||
using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
class BufferForC : public Buffer {
|
||||
public:
|
||||
BufferForC(const char *data, size_t len, on_mk_buffer_free cb, void *user_data) {
|
||||
if (len <= 0) {
|
||||
len = strlen(data);
|
||||
}
|
||||
if (!cb) {
|
||||
auto ptr = malloc(len);
|
||||
memcpy(ptr, data, len);
|
||||
data = (char *) ptr;
|
||||
|
||||
cb = [](void *user_data, void *data) {
|
||||
free(data);
|
||||
};
|
||||
}
|
||||
_data = (char *) data;
|
||||
_size = len;
|
||||
_cb = cb;
|
||||
_user_data = user_data;
|
||||
}
|
||||
|
||||
~BufferForC() override {
|
||||
_cb(_user_data, _data);
|
||||
}
|
||||
|
||||
char *data() const override {
|
||||
return _data;
|
||||
}
|
||||
|
||||
size_t size() const override {
|
||||
return _size;
|
||||
}
|
||||
|
||||
private:
|
||||
char *_data;
|
||||
size_t _size;
|
||||
on_mk_buffer_free _cb;
|
||||
void *_user_data;
|
||||
};
|
||||
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_from_char(const char *data, size_t len, on_mk_buffer_free cb, void *user_data) {
|
||||
assert(data);
|
||||
return new Buffer::Ptr(std::make_shared<BufferForC>(data, len, cb, user_data));
|
||||
}
|
||||
|
||||
API_EXPORT mk_buffer API_CALL mk_buffer_ref(mk_buffer buffer) {
|
||||
assert(buffer);
|
||||
return new Buffer::Ptr(*((Buffer::Ptr *) buffer));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_buffer_unref(mk_buffer buffer) {
|
||||
assert(buffer);
|
||||
delete (Buffer::Ptr *) buffer;
|
||||
}
|
||||
|
||||
API_EXPORT const char *API_CALL mk_buffer_get_data(mk_buffer buffer) {
|
||||
assert(buffer);
|
||||
return (*((Buffer::Ptr *) buffer))->data();
|
||||
}
|
||||
|
||||
API_EXPORT size_t API_CALL mk_buffer_get_size(mk_buffer buffer) {
|
||||
assert(buffer);
|
||||
return (*((Buffer::Ptr *) buffer))->size();
|
||||
}
|
||||
|
||||
API_EXPORT const char* API_CALL mk_sock_info_peer_ip(const mk_sock_info ctx, char *buf){
|
||||
assert(ctx);
|
||||
SockInfo *sock = (SockInfo *)ctx;
|
||||
@ -53,34 +119,54 @@ API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int er
|
||||
session->safeShutdown(SockException((ErrCode)err,err_msg));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data, size_t len){
|
||||
assert(ctx && data);
|
||||
if(!len){
|
||||
len = strlen(data);
|
||||
}
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer(const mk_tcp_session ctx, mk_buffer buffer) {
|
||||
assert(ctx && buffer);
|
||||
TcpSessionForC *session = (TcpSessionForC *) ctx;
|
||||
session->SockSender::send(data,len);
|
||||
session->send(*((Buffer::Ptr *) buffer));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,size_t len){
|
||||
assert(ctx && data);
|
||||
if (!len) {
|
||||
len = strlen(data);
|
||||
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx, const char *data, size_t len) {
|
||||
auto buffer = mk_buffer_from_char(data, len, nullptr, nullptr);
|
||||
mk_tcp_session_send_buffer(ctx, buffer);
|
||||
mk_buffer_unref(buffer);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_buffer_safe(const mk_tcp_session ctx, mk_buffer buffer) {
|
||||
assert(ctx && buffer);
|
||||
try {
|
||||
std::weak_ptr<TcpSession> weak_session = ((TcpSessionForC *) ctx)->shared_from_this();
|
||||
std::string str = std::string(data,len);
|
||||
((TcpSessionForC *)ctx)->async([weak_session,str](){
|
||||
auto ref = mk_buffer_ref(buffer);
|
||||
((TcpSessionForC *) ctx)->async([weak_session, ref]() {
|
||||
auto session_session = weak_session.lock();
|
||||
if (session_session) {
|
||||
session_session->SockSender::send(str);
|
||||
session_session->send(*((Buffer::Ptr *) ref));
|
||||
}
|
||||
mk_buffer_unref(ref);
|
||||
});
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << "can not got the strong pionter of this mk_tcp_session:" << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORT mk_tcp_session_ref API_CALL mk_tcp_session_ref_from(const mk_tcp_session ctx) {
|
||||
auto ref = ((TcpSessionForC *) ctx)->shared_from_this();
|
||||
return new std::shared_ptr<TcpSessionForC>(std::dynamic_pointer_cast<TcpSessionForC>(ref));
|
||||
}
|
||||
|
||||
API_EXPORT void mk_tcp_session_ref_release(const mk_tcp_session_ref ref) {
|
||||
delete (std::shared_ptr<TcpSessionForC> *) ref;
|
||||
}
|
||||
|
||||
API_EXPORT mk_tcp_session mk_tcp_session_from_ref(const mk_tcp_session_ref ref) {
|
||||
return ((std::shared_ptr<TcpSessionForC> *) ref)->get();
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx, const char *data, size_t len) {
|
||||
auto buffer = mk_buffer_from_char(data, len, nullptr, nullptr);
|
||||
mk_tcp_session_send_buffer_safe(ctx, buffer);
|
||||
mk_buffer_unref(buffer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////TcpSessionForC////////////////////////////////////////////////
|
||||
static TcpServer::Ptr s_tcp_server[4];
|
||||
static mk_tcp_session_events s_events_server = {0};
|
||||
@ -94,7 +180,7 @@ TcpSessionForC::TcpSessionForC(const Socket::Ptr &pSock) : TcpSession(pSock) {
|
||||
|
||||
void TcpSessionForC::onRecv(const Buffer::Ptr &buffer) {
|
||||
if (s_events_server.on_mk_tcp_session_data) {
|
||||
s_events_server.on_mk_tcp_session_data(_local_port,this, buffer->data(), buffer->size());
|
||||
s_events_server.on_mk_tcp_session_data(_local_port, this, (mk_buffer)&buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,10 +255,9 @@ TcpClientForC::TcpClientForC(mk_tcp_client_events *events){
|
||||
_events = *events;
|
||||
}
|
||||
|
||||
|
||||
void TcpClientForC::onRecv(const Buffer::Ptr &pBuf) {
|
||||
if (_events.on_mk_tcp_client_data) {
|
||||
_events.on_mk_tcp_client_data(_client,pBuf->data(),pBuf->size());
|
||||
_events.on_mk_tcp_client_data(_client, (mk_buffer)&pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,24 +331,36 @@ API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *ho
|
||||
(*client)->startConnect(host,port);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len){
|
||||
assert(ctx && data);
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer(mk_tcp_client ctx, mk_buffer buffer) {
|
||||
assert(ctx && buffer);
|
||||
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *) ctx;
|
||||
(*client)->SockSender::send(data,len);
|
||||
(*client)->send(*((Buffer::Ptr *) buffer));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len) {
|
||||
auto buffer = mk_buffer_from_char(data, len, nullptr, nullptr);
|
||||
mk_tcp_client_send_buffer(ctx, buffer);
|
||||
mk_buffer_unref(buffer);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_buffer_safe(mk_tcp_client ctx, mk_buffer buffer) {
|
||||
assert(ctx && buffer);
|
||||
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *) ctx;
|
||||
std::weak_ptr<TcpClient> weakClient = *client;
|
||||
auto ref = mk_buffer_ref(buffer);
|
||||
(*client)->async([weakClient, ref]() {
|
||||
auto strongClient = weakClient.lock();
|
||||
if (strongClient) {
|
||||
strongClient->send(*((Buffer::Ptr *) ref));
|
||||
}
|
||||
mk_buffer_unref(ref);
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_client_send_safe(mk_tcp_client ctx, const char *data, int len){
|
||||
assert(ctx && data);
|
||||
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *)ctx;
|
||||
std::weak_ptr<TcpClient> weakClient = *client;
|
||||
auto buf = BufferRaw::create();
|
||||
buf->assign(data,len);
|
||||
(*client)->async([weakClient,buf](){
|
||||
auto strongClient = weakClient.lock();
|
||||
if(strongClient){
|
||||
strongClient->send(buf);
|
||||
}
|
||||
});
|
||||
auto buffer = mk_buffer_from_char(data, len, nullptr, nullptr);
|
||||
mk_tcp_client_send_buffer_safe(ctx, buffer);
|
||||
mk_buffer_unref(buffer);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_tcp_client_set_user_data(mk_tcp_client ctx,void *user_data){
|
||||
|
@ -44,6 +44,15 @@ API_EXPORT void API_CALL mk_async_do(mk_thread ctx,on_mk_async cb, void *user_da
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_async_do_delay(mk_thread ctx, size_t ms, on_mk_async cb, void *user_data) {
|
||||
assert(ctx && cb && ms);
|
||||
EventPoller *poller = (EventPoller *) ctx;
|
||||
poller->doDelayTask(ms, [cb, user_data]() {
|
||||
cb(user_data);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_sync_do(mk_thread ctx,on_mk_async cb, void *user_data){
|
||||
assert(ctx && cb);
|
||||
EventPoller *poller = (EventPoller *)ctx;
|
||||
@ -108,3 +117,51 @@ API_EXPORT void API_CALL mk_timer_release(mk_timer ctx){
|
||||
(*obj)->cancel();
|
||||
delete obj;
|
||||
}
|
||||
|
||||
class WorkThreadPoolForC : public TaskExecutorGetterImp {
|
||||
public:
|
||||
~WorkThreadPoolForC() override = default;
|
||||
|
||||
WorkThreadPoolForC(const char *name, size_t n_thread, int priority) {
|
||||
//最低优先级
|
||||
addPoller(name, n_thread, (ThreadPool::Priority) priority, false);
|
||||
}
|
||||
|
||||
EventPoller::Ptr getPoller() {
|
||||
return dynamic_pointer_cast<EventPoller>(getExecutor());
|
||||
}
|
||||
};
|
||||
|
||||
API_EXPORT mk_thread_pool API_CALL mk_thread_pool_create(const char *name, size_t n_thread, int priority) {
|
||||
return new WorkThreadPoolForC(name, n_thread, priority);
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_thread_pool_release(mk_thread_pool pool) {
|
||||
assert(pool);
|
||||
delete (WorkThreadPoolForC *) pool;
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT mk_thread API_CALL mk_thread_from_thread_pool(mk_thread_pool pool) {
|
||||
assert(pool);
|
||||
return ((WorkThreadPoolForC *) pool)->getPoller().get();
|
||||
}
|
||||
|
||||
API_EXPORT mk_sem API_CALL mk_sem_create() {
|
||||
return new toolkit::semaphore;
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_sem_release(mk_sem sem) {
|
||||
assert(sem);
|
||||
delete (toolkit::semaphore *) sem;
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_sem_post(mk_sem sem, size_t n) {
|
||||
assert(sem);
|
||||
((toolkit::semaphore *) sem)->post(n);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_sem_wait(mk_sem sem) {
|
||||
assert(sem);
|
||||
((toolkit::semaphore *) sem)->wait();
|
||||
}
|
196
api/source/mk_track.cpp
Normal file
196
api/source/mk_track.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "mk_track.h"
|
||||
#include "Extension/Track.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
class VideoTrackForC : public VideoTrack {
|
||||
public:
|
||||
VideoTrackForC(int codec_id, codec_args *args) {
|
||||
_codec_id = (CodecId) codec_id;
|
||||
if (args) {
|
||||
_args = *args;
|
||||
} else {
|
||||
memset(&_args, 0, sizeof(_args));
|
||||
}
|
||||
}
|
||||
|
||||
~VideoTrackForC() override = default;
|
||||
|
||||
int getVideoHeight() const override {
|
||||
return _args.video.height;
|
||||
}
|
||||
|
||||
int getVideoWidth() const override {
|
||||
return _args.video.width;
|
||||
}
|
||||
|
||||
float getVideoFps() const override {
|
||||
return _args.video.fps;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override {
|
||||
return _codec_id;
|
||||
}
|
||||
|
||||
bool ready() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
Track::Ptr clone() override {
|
||||
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
|
||||
}
|
||||
|
||||
Sdp::Ptr getSdp() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
CodecId _codec_id;
|
||||
codec_args _args;
|
||||
};
|
||||
|
||||
class AudioTrackForC : public AudioTrackImp {
|
||||
public:
|
||||
~AudioTrackForC() override = default;
|
||||
|
||||
AudioTrackForC(int codec_id, codec_args *args) :
|
||||
AudioTrackImp((CodecId) codec_id, args->audio.sample_rate, args->audio.channels, 16) {}
|
||||
|
||||
Track::Ptr clone() override {
|
||||
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
|
||||
}
|
||||
|
||||
Sdp::Ptr getSdp() override {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
API_EXPORT mk_track API_CALL mk_track_create(int codec_id, codec_args *args) {
|
||||
switch (getTrackType((CodecId) codec_id)) {
|
||||
case TrackVideo: return new Track::Ptr(std::make_shared<VideoTrackForC>(codec_id, args));
|
||||
case TrackAudio: return new Track::Ptr(std::make_shared<AudioTrackForC>(codec_id, args));
|
||||
default: WarnL << "unrecognized codec:" << codec_id; return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_track_unref(mk_track track) {
|
||||
assert(track);
|
||||
delete (Track::Ptr *)track;
|
||||
}
|
||||
|
||||
API_EXPORT mk_track API_CALL mk_track_ref(mk_track track) {
|
||||
assert(track);
|
||||
return new Track::Ptr(*( (Track::Ptr *)track));
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_codec_id(mk_track track) {
|
||||
assert(track);
|
||||
return (*((Track::Ptr *) track))->getCodecId();
|
||||
}
|
||||
|
||||
API_EXPORT const char *API_CALL mk_track_codec_name(mk_track track) {
|
||||
assert(track);
|
||||
return (*((Track::Ptr *) track))->getCodecName();
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_bit_rate(mk_track track) {
|
||||
assert(track);
|
||||
return (*((Track::Ptr *) track))->getBitRate();
|
||||
}
|
||||
|
||||
API_EXPORT void *API_CALL mk_track_add_delegate(mk_track track, on_mk_frame_out cb, void *user_data) {
|
||||
assert(track && cb);
|
||||
auto delegate = std::make_shared<FrameWriterInterfaceHelper>([cb, user_data](const Frame::Ptr &frame) {
|
||||
cb(user_data, (mk_frame) &frame);
|
||||
return true;
|
||||
});
|
||||
(*((Track::Ptr *) track))->addDelegate(delegate);
|
||||
return delegate.get();
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_track_del_delegate(mk_track track, void *tag) {
|
||||
assert(track && tag);
|
||||
(*((Track::Ptr *) track))->delDelegate((FrameWriterInterface *) tag);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_track_input_frame(mk_track track, mk_frame frame) {
|
||||
assert(track && frame);
|
||||
(*((Track::Ptr *) track))->inputFrame((*((Frame::Ptr *) frame)));
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_is_video(mk_track track) {
|
||||
assert(track);
|
||||
return (*((Track::Ptr *) track))->getTrackType() == TrackVideo;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_video_width(mk_track track) {
|
||||
assert(track);
|
||||
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *) track)));
|
||||
if (video) {
|
||||
return video->getVideoWidth();
|
||||
}
|
||||
WarnL << "not video track";
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_video_height(mk_track track) {
|
||||
assert(track);
|
||||
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *) track)));
|
||||
if (video) {
|
||||
return video->getVideoHeight();
|
||||
}
|
||||
WarnL << "not video track";
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_video_fps(mk_track track) {
|
||||
assert(track);
|
||||
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *) track)));
|
||||
if (video) {
|
||||
return video->getVideoFps();
|
||||
}
|
||||
WarnL << "not video track";
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_rate(mk_track track) {
|
||||
assert(track);
|
||||
auto audio = dynamic_pointer_cast<AudioTrack>((*((Track::Ptr *) track)));
|
||||
if (audio) {
|
||||
return audio->getAudioSampleRate();
|
||||
}
|
||||
WarnL << "not audio track";
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_audio_channel(mk_track track) {
|
||||
assert(track);
|
||||
auto audio = dynamic_pointer_cast<AudioTrack>((*((Track::Ptr *) track)));
|
||||
if (audio) {
|
||||
return audio->getAudioChannel();
|
||||
}
|
||||
WarnL << "not audio track";
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_track_audio_sample_bit(mk_track track) {
|
||||
assert(track);
|
||||
auto audio = dynamic_pointer_cast<AudioTrack>((*((Track::Ptr *) track)));
|
||||
if (audio) {
|
||||
return audio->getAudioSampleBit();
|
||||
}
|
||||
WarnL << "not audio track";
|
||||
return 0;
|
||||
}
|
126
api/source/mk_transcode.cpp
Normal file
126
api/source/mk_transcode.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "mk_transcode.h"
|
||||
#include "Extension/Track.h"
|
||||
|
||||
using namespace mediakit;
|
||||
|
||||
#ifdef ENABLE_FFMPEG
|
||||
|
||||
#include "Codec/Transcode.h"
|
||||
|
||||
API_EXPORT mk_decoder API_CALL mk_decoder_create(mk_track track, int thread_num) {
|
||||
assert(track);
|
||||
return new FFmpegDecoder(*((Track::Ptr *)track), thread_num);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_decoder_release(mk_decoder ctx, int flush_frame) {
|
||||
assert(ctx);
|
||||
auto decoder = (FFmpegDecoder *)ctx;
|
||||
if (flush_frame) {
|
||||
decoder->stopThread(false);
|
||||
}
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_decoder_decode(mk_decoder ctx, mk_frame frame, int async, int enable_merge) {
|
||||
assert(ctx && frame);
|
||||
((FFmpegDecoder *)ctx)->inputFrame(*((Frame::Ptr *)frame), false, async, enable_merge);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_decoder_set_max_async_frame_size(mk_decoder ctx, size_t size) {
|
||||
assert(ctx && size);
|
||||
((FFmpegDecoder *)ctx)->setMaxTaskSize(size);
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_decoder_set_cb(mk_decoder ctx, on_mk_decode cb, void *user_data) {
|
||||
assert(ctx && cb);
|
||||
((FFmpegDecoder *)ctx)->setOnDecode([cb, user_data](const FFmpegFrame::Ptr &pix_frame) {
|
||||
cb(user_data, (mk_frame_pix)&pix_frame);
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT const AVCodecContext *API_CALL mk_decoder_get_context(mk_decoder ctx) {
|
||||
assert(ctx);
|
||||
return ((FFmpegDecoder *)ctx)->getContext();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_ref(mk_frame_pix frame) {
|
||||
assert(frame);
|
||||
return new FFmpegFrame::Ptr(*(FFmpegFrame::Ptr *)frame);
|
||||
}
|
||||
|
||||
API_EXPORT mk_frame_pix API_CALL mk_frame_pix_from_av_frame(AVFrame *frame) {
|
||||
assert(frame);
|
||||
return new FFmpegFrame::Ptr(std::make_shared<FFmpegFrame>(
|
||||
std::shared_ptr<AVFrame>(av_frame_clone(frame), [](AVFrame *frame) { av_frame_free(&frame); })));
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL mk_frame_pix_unref(mk_frame_pix frame) {
|
||||
assert(frame);
|
||||
delete (FFmpegFrame::Ptr *)frame;
|
||||
}
|
||||
|
||||
API_EXPORT AVFrame *API_CALL mk_frame_pix_get_av_frame(mk_frame_pix frame) {
|
||||
assert(frame);
|
||||
return (*(FFmpegFrame::Ptr *)frame)->get();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
API_EXPORT mk_swscale mk_swscale_create(int output, int width, int height) {
|
||||
return new FFmpegSws((AVPixelFormat)output, width, height);
|
||||
}
|
||||
|
||||
API_EXPORT void mk_swscale_release(mk_swscale ctx) {
|
||||
delete (FFmpegSws *)ctx;
|
||||
}
|
||||
|
||||
API_EXPORT int mk_swscale_input_frame(mk_swscale ctx, mk_frame_pix frame, uint8_t *data) {
|
||||
return ((FFmpegSws *)ctx)->inputFrame(*(FFmpegFrame::Ptr *)frame, data);
|
||||
}
|
||||
|
||||
API_EXPORT mk_frame_pix mk_swscale_input_frame2(mk_swscale ctx, mk_frame_pix frame) {
|
||||
return new FFmpegFrame::Ptr(((FFmpegSws *)ctx)->inputFrame(*(FFmpegFrame::Ptr *)frame));
|
||||
}
|
||||
|
||||
API_EXPORT uint8_t **API_CALL mk_get_av_frame_data(AVFrame *frame) {
|
||||
return frame->data;
|
||||
}
|
||||
|
||||
API_EXPORT int *API_CALL mk_get_av_frame_line_size(AVFrame *frame) {
|
||||
return frame->linesize;
|
||||
}
|
||||
|
||||
API_EXPORT int64_t API_CALL mk_get_av_frame_dts(AVFrame *frame) {
|
||||
return frame->pkt_dts;
|
||||
}
|
||||
|
||||
API_EXPORT int64_t API_CALL mk_get_av_frame_pts(AVFrame *frame) {
|
||||
return frame->pts;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_get_av_frame_width(AVFrame *frame) {
|
||||
return frame->width;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_get_av_frame_height(AVFrame *frame) {
|
||||
return frame->height;
|
||||
}
|
||||
|
||||
API_EXPORT int API_CALL mk_get_av_frame_format(AVFrame *frame) {
|
||||
return frame->format;
|
||||
}
|
||||
|
||||
|
||||
#endif //ENABLE_FFMPEG
|
6
api/tests/CMakeLists.sample
Normal file
6
api/tests/CMakeLists.sample
Normal file
@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.1.3)
|
||||
project(player)
|
||||
include_directories("../../include")
|
||||
link_directories("../../so")
|
||||
add_executable(player "./player_opencv.c")
|
||||
target_link_libraries(player mk_api ssl crypto avcodec swscale swresample avutil x264 openh264 x265)
|
@ -22,14 +22,17 @@ static void s_on_exit(int sig) {
|
||||
exit_flag = 1;
|
||||
}
|
||||
|
||||
static void on_h264_frame(void *user_data, mk_h264_splitter splitter, const char *frame, int size) {
|
||||
static void on_h264_frame(void *user_data, mk_h264_splitter splitter, const char *data, int size) {
|
||||
#ifdef _WIN32
|
||||
Sleep(40);
|
||||
#else
|
||||
usleep(40 * 1000);
|
||||
#endif
|
||||
mk_media media = (mk_media) user_data;
|
||||
mk_media_input_h264(media, frame, size, 0, 0);
|
||||
static int dts = 0;
|
||||
mk_frame frame = mk_frame_create(MKCodecH264, dts, dts, data, size, NULL, NULL);
|
||||
dts += 40;
|
||||
mk_media_input_frame((mk_media) user_data, frame);
|
||||
mk_frame_unref(frame);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@ -60,7 +63,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
||||
//h264的codec
|
||||
mk_media_init_video(media, 0, 0, 0, 0);
|
||||
mk_media_init_video(media, 0, 0, 0, 0, 2 * 104 * 1024);
|
||||
mk_media_init_complete(media);
|
||||
|
||||
//创建h264分帧器
|
||||
|
61
api/tests/httpclient.c
Normal file
61
api/tests/httpclient.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "mk_mediakit.h"
|
||||
|
||||
typedef struct {
|
||||
mk_sem sem;
|
||||
mk_http_requester requester;
|
||||
} Context;
|
||||
|
||||
static API_CALL void on_requester_complete(void *user_data, int code, const char *err_msg){
|
||||
Context *ctx = (Context *)user_data;
|
||||
log_debug("code: %d %s", code, err_msg);
|
||||
size_t res_len = 0;
|
||||
log_debug("response: %s %s", mk_http_requester_get_response_status(ctx->requester),
|
||||
mk_http_requester_get_response_body(ctx->requester, &res_len));
|
||||
mk_sem_post(ctx->sem, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
mk_config config = {
|
||||
.ini = NULL,
|
||||
.ini_is_path = 0,
|
||||
.log_level = 0,
|
||||
.log_mask = LOG_CONSOLE,
|
||||
.ssl = NULL,
|
||||
.ssl_is_path = 1,
|
||||
.ssl_pwd = NULL,
|
||||
.thread_num = 0
|
||||
};
|
||||
mk_env_init(&config);
|
||||
|
||||
mk_http_requester requester = mk_http_requester_create();
|
||||
mk_http_requester_set_method(requester, "POST");
|
||||
|
||||
mk_http_body body = mk_http_body_from_string("tn=monline_7_dg&ie=utf-8&wd=test", 0);
|
||||
mk_http_requester_set_body(requester, body);
|
||||
mk_http_body_release(body);
|
||||
|
||||
mk_sem sem = mk_sem_create();
|
||||
|
||||
Context ctx = {.requester = requester, .sem = sem};
|
||||
|
||||
mk_http_requester_set_cb(requester, on_requester_complete, &ctx);
|
||||
mk_http_requester_start(requester, "http://www.baidu.com/baidu", 10);
|
||||
|
||||
//等待http请求完毕
|
||||
mk_sem_wait(sem);
|
||||
|
||||
mk_sem_release(sem);
|
||||
mk_http_requester_release(requester);
|
||||
return 0;
|
||||
}
|
108
api/tests/player_opencv.c
Normal file
108
api/tests/player_opencv.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
||||
*
|
||||
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
||||
*
|
||||
* Use of this source code is governed by MIT license that can be found in the
|
||||
* LICENSE file in the root of the source tree. All contributing project authors
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "mk_mediakit.h"
|
||||
|
||||
typedef struct {
|
||||
mk_player player;
|
||||
mk_decoder video_decoder;
|
||||
mk_swscale swscale;
|
||||
} Context;
|
||||
|
||||
void API_CALL on_track_frame_out(void *user_data, mk_frame frame) {
|
||||
Context *ctx = (Context *) user_data;
|
||||
mk_decoder_decode(ctx->video_decoder, frame, 1, 1);
|
||||
}
|
||||
|
||||
void API_CALL on_frame_decode(void *user_data, mk_frame_pix frame) {
|
||||
Context *ctx = (Context *) user_data;
|
||||
int w = mk_get_av_frame_width(mk_frame_pix_get_av_frame(frame));
|
||||
int h = mk_get_av_frame_height(mk_frame_pix_get_av_frame(frame));
|
||||
|
||||
#if 1
|
||||
uint8_t *brg24 = malloc(w * h * 3);
|
||||
mk_swscale_input_frame(ctx->swscale, frame, brg24);
|
||||
free(brg24);
|
||||
#else
|
||||
//todo 此处转换为opencv对象
|
||||
cv::Mat *mat = new cv::Mat();
|
||||
mat->create(h, w, CV_8UC3);
|
||||
mk_swscale_input_frame(ctx->swscale, frame, (uint8_t *) mat->data);
|
||||
#endif
|
||||
log_trace("decode frame output, pts:%d, w:%d, h:%d", mk_get_av_frame_dts(mk_frame_pix_get_av_frame(frame)), w, h);
|
||||
}
|
||||
|
||||
void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[],
|
||||
int track_count) {
|
||||
Context *ctx = (Context *) user_data;
|
||||
if (err_code == 0) {
|
||||
//success
|
||||
log_debug("play success!");
|
||||
for (int i = 0; i < track_count; ++i) {
|
||||
if (mk_track_is_video(tracks[i])) {
|
||||
log_info("got video track: %s", mk_track_codec_name(tracks[i]));
|
||||
ctx->video_decoder = mk_decoder_create(tracks[i], 0);
|
||||
mk_decoder_set_cb(ctx->video_decoder, on_frame_decode, user_data);
|
||||
//监听track数据回调
|
||||
mk_track_add_delegate(tracks[i], on_track_frame_out, user_data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_warn("play failed: %d %s", err_code, err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
void API_CALL on_mk_shutdown_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[], int track_count) {
|
||||
log_warn("play interrupted: %d %s", err_code, err_msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
mk_config config = {
|
||||
.ini = NULL,
|
||||
.ini_is_path = 0,
|
||||
.log_level = 0,
|
||||
.log_mask = LOG_CONSOLE,
|
||||
.ssl = NULL,
|
||||
.ssl_is_path = 1,
|
||||
.ssl_pwd = NULL,
|
||||
.thread_num = 0
|
||||
};
|
||||
mk_env_init(&config);
|
||||
if (argc != 2) {
|
||||
printf("Usage: ./player url\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Context ctx;
|
||||
memset(&ctx, 0, sizeof(Context));
|
||||
|
||||
ctx.player = mk_player_create();
|
||||
ctx.swscale = mk_swscale_create(3, 0, 0);
|
||||
mk_player_set_on_result(ctx.player, on_mk_play_event_func, &ctx);
|
||||
mk_player_set_on_shutdown(ctx.player, on_mk_shutdown_func, &ctx);
|
||||
mk_player_play(ctx.player, argv[1]);
|
||||
|
||||
log_info("enter any key to exit");
|
||||
getchar();
|
||||
|
||||
if (ctx.player) {
|
||||
mk_player_release(ctx.player);
|
||||
}
|
||||
if (ctx.video_decoder) {
|
||||
mk_decoder_release(ctx.video_decoder, 1);
|
||||
}
|
||||
if (ctx.swscale) {
|
||||
mk_swscale_release(ctx.swscale);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -8,16 +8,9 @@
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include "mk_mediakit.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
mk_player player;
|
||||
mk_media media;
|
||||
@ -84,7 +77,12 @@ void API_CALL on_mk_media_source_regist_func(void *user_data, mk_media_source se
|
||||
}
|
||||
}
|
||||
|
||||
void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *err_msg) {
|
||||
void API_CALL on_track_frame_out(void *user_data, mk_frame frame) {
|
||||
Context *ctx = (Context *) user_data;
|
||||
mk_media_input_frame(ctx->media, frame);
|
||||
}
|
||||
|
||||
void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *err_msg, mk_track tracks[], int track_count) {
|
||||
Context *ctx = (Context *) user_data;
|
||||
release_media(&(ctx->media));
|
||||
release_pusher(&(ctx->pusher));
|
||||
@ -92,21 +90,9 @@ void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *e
|
||||
//success
|
||||
log_debug("play success!");
|
||||
ctx->media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
|
||||
|
||||
int video_codec = mk_player_video_codec_id(ctx->player);
|
||||
int audio_codec = mk_player_audio_codec_id(ctx->player);
|
||||
if(video_codec != -1){
|
||||
mk_media_init_video(ctx->media, video_codec,
|
||||
mk_player_video_width(ctx->player),
|
||||
mk_player_video_height(ctx->player),
|
||||
mk_player_video_fps(ctx->player));
|
||||
}
|
||||
|
||||
if(audio_codec != -1){
|
||||
mk_media_init_audio(ctx->media,audio_codec,
|
||||
mk_player_audio_samplerate(ctx->player),
|
||||
mk_player_audio_channel(ctx->player),
|
||||
mk_player_audio_bit(ctx->player));
|
||||
for (int i = 0; i < track_count; ++i) {
|
||||
mk_media_init_track(ctx->media, tracks[i]);
|
||||
mk_track_add_delegate(tracks[i], on_track_frame_out, user_data);
|
||||
}
|
||||
mk_media_init_complete(ctx->media);
|
||||
mk_media_set_on_regist(ctx->media, on_mk_media_source_regist_func, ctx);
|
||||
@ -116,49 +102,15 @@ void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *e
|
||||
}
|
||||
}
|
||||
|
||||
void API_CALL on_mk_play_data_func(void *user_data,int track_type, int codec_id,void *data,size_t len, uint32_t dts,uint32_t pts){
|
||||
Context *ctx = (Context *) user_data;
|
||||
switch (codec_id) {
|
||||
case 0 : {
|
||||
//h264
|
||||
mk_media_input_h264(ctx->media, data, (int)len, dts, pts);
|
||||
break;
|
||||
}
|
||||
case 1 : {
|
||||
//h265
|
||||
mk_media_input_h265(ctx->media, data, (int)len, dts, pts);
|
||||
break;
|
||||
}
|
||||
case 2 : {
|
||||
//aac, aac头7个字节
|
||||
mk_media_input_aac(ctx->media, (uint8_t*)data + 7, (int)len, dts, data);
|
||||
break;
|
||||
}
|
||||
case 3 : //g711a
|
||||
case 4 : //g711u
|
||||
case 5 : //opus
|
||||
mk_media_input_audio(ctx->media, data, (int) len, dts);
|
||||
break;
|
||||
|
||||
default: {
|
||||
log_warn("unknown codec: %d", codec_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context_start(Context *ctx, const char *url_pull, const char *url_push){
|
||||
release_player(&(ctx->player));
|
||||
ctx->player = mk_player_create();
|
||||
mk_player_set_on_result(ctx->player, on_mk_play_event_func, ctx);
|
||||
mk_player_set_on_shutdown(ctx->player, on_mk_play_event_func, ctx);
|
||||
mk_player_set_on_data(ctx->player, on_mk_play_data_func, ctx);
|
||||
mk_player_play(ctx->player, url_pull);
|
||||
strcpy(ctx->push_url, url_push);
|
||||
}
|
||||
|
||||
//create_player("http://hls.weathertv.cn/tslslive/qCFIfHB/hls/live_sd.m3u8");
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
mk_config config = {
|
||||
.ini = NULL,
|
||||
@ -172,6 +124,11 @@ int main(int argc, char *argv[]){
|
||||
};
|
||||
mk_env_init(&config);
|
||||
|
||||
if (argc != 3) {
|
||||
printf("Usage: ./pusher.c pull_url push_url\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//可以通过
|
||||
//rtmp://127.0.0.1/live/test
|
||||
//rtsp://127.0.0.1/live/test
|
||||
@ -183,16 +140,10 @@ int main(int argc, char *argv[]){
|
||||
memset(ctx, 0, sizeof(Context));
|
||||
|
||||
//推流给自己测试,当然也可以推流给其他服务器测试
|
||||
context_start(ctx, "http://hls.weathertv.cn/tslslive/qCFIfHB/hls/live_sd.m3u8", "rtsp://127.0.0.1/live/rtsp_push");
|
||||
context_start(ctx, argv[1], argv[2]);
|
||||
|
||||
int i = 10 * 60;
|
||||
while(--i){
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
}
|
||||
log_info("enter any key to exit");
|
||||
getchar();
|
||||
|
||||
release_context(&ctx);
|
||||
return 0;
|
||||
|
@ -8,18 +8,8 @@
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include "mk_mediakit.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
|
||||
#include "unistd.h"
|
||||
|
||||
#endif
|
||||
|
||||
#define LOG_LEV 4
|
||||
|
||||
/**
|
||||
@ -396,10 +386,6 @@ void API_CALL on_mk_flow_report(const mk_media_info url_info,
|
||||
(int)mk_sock_info_peer_port(sender));
|
||||
}
|
||||
|
||||
static int flag = 1;
|
||||
static void s_on_exit(int sig){
|
||||
flag = 0;
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
char *ini_path = mk_util_get_exe_dir("c_api.ini");
|
||||
char *ssl_path = mk_util_get_exe_dir("ssl.p12");
|
||||
@ -444,17 +430,11 @@ int main(int argc, char *argv[]) {
|
||||
.on_mk_flow_report = on_mk_flow_report
|
||||
};
|
||||
mk_events_listen(&events);
|
||||
|
||||
log_info("media server %s", "stared!");
|
||||
|
||||
signal(SIGINT, s_on_exit );// 设置退出信号
|
||||
while (flag) {
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
}
|
||||
log_info("enter any key to exit");
|
||||
getchar();
|
||||
|
||||
mk_stop_all_server();
|
||||
return 0;
|
||||
}
|
@ -8,26 +8,15 @@
|
||||
* may be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "mk_mediakit.h"
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#define LOG_LEV 4
|
||||
//修改此宏,可以选择协议类型
|
||||
#define TCP_TYPE mk_type_ws
|
||||
|
||||
static int flag = 1;
|
||||
static void s_on_exit(int sig){
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct {
|
||||
mk_tcp_session _session;
|
||||
@ -52,11 +41,15 @@ void API_CALL on_mk_tcp_session_create(uint16_t server_port,mk_tcp_session sessi
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
*/
|
||||
void API_CALL on_mk_tcp_session_data(uint16_t server_port,mk_tcp_session session,const char *data,size_t len){
|
||||
void API_CALL on_mk_tcp_session_data(uint16_t server_port,mk_tcp_session session, mk_buffer buffer){
|
||||
char ip[64];
|
||||
log_printf(LOG_LEV,"from %s %d, data[%d]: %s",mk_tcp_session_peer_ip(session,ip),(int)mk_tcp_session_peer_port(session), len,data);
|
||||
log_printf(LOG_LEV,"from %s %d, data[%d]: %s",
|
||||
mk_tcp_session_peer_ip(session,ip),
|
||||
(int)mk_tcp_session_peer_port(session),
|
||||
mk_buffer_get_size(buffer),
|
||||
mk_buffer_get_data(buffer));
|
||||
mk_tcp_session_send(session,"echo:",0);
|
||||
mk_tcp_session_send(session,data,len);
|
||||
mk_tcp_session_send_buffer(session, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,8 +122,8 @@ void API_CALL on_mk_tcp_client_disconnect(mk_tcp_client client,int code,const ch
|
||||
* @param data 数据指针
|
||||
* @param len 数据长度
|
||||
*/
|
||||
void API_CALL on_mk_tcp_client_data(mk_tcp_client client,const char *data,size_t len){
|
||||
log_printf(LOG_LEV,"data[%d]:%s",len,data);
|
||||
void API_CALL on_mk_tcp_client_data(mk_tcp_client client, mk_buffer buffer){
|
||||
log_printf(LOG_LEV, "data[%d]:%s", mk_buffer_get_size(buffer), mk_buffer_get_data(buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,14 +196,9 @@ int main(int argc, char *argv[]) {
|
||||
test_server();
|
||||
test_client();
|
||||
|
||||
signal(SIGINT, s_on_exit );// 设置退出信号
|
||||
while (flag) {
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
}
|
||||
log_info("enter any key to exit");
|
||||
getchar();
|
||||
|
||||
mk_stop_all_server();
|
||||
return 0;
|
||||
}
|
@ -91,6 +91,9 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{
|
||||
//缓存为空
|
||||
return false;
|
||||
}
|
||||
if (!frame) {
|
||||
return true;
|
||||
}
|
||||
switch (_type) {
|
||||
case none : {
|
||||
//frame不是完整的帧,我们合并为一帧
|
||||
@ -180,6 +183,10 @@ bool FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb, Buffer
|
||||
_have_decode_able_frame = false;
|
||||
}
|
||||
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frame->decodeAble()) {
|
||||
_have_decode_able_frame = true;
|
||||
}
|
||||
|
@ -310,45 +310,33 @@ private:
|
||||
*/
|
||||
class FrameDispatcher : public FrameWriterInterface {
|
||||
public:
|
||||
typedef std::shared_ptr<FrameDispatcher> Ptr;
|
||||
|
||||
FrameDispatcher(){}
|
||||
virtual ~FrameDispatcher(){}
|
||||
using Ptr = std::shared_ptr<FrameDispatcher>;
|
||||
FrameDispatcher() = default;
|
||||
~FrameDispatcher() override = default;
|
||||
|
||||
/**
|
||||
* 添加代理
|
||||
*/
|
||||
void addDelegate(const FrameWriterInterface::Ptr &delegate) {
|
||||
//_delegates_write可能多线程同时操作
|
||||
std::lock_guard<std::mutex> lck(_mtx);
|
||||
_delegates_write.emplace(delegate.get(),delegate);
|
||||
_need_update = true;
|
||||
_delegates.emplace(delegate.get(), delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除代理
|
||||
*/
|
||||
void delDelegate(FrameWriterInterface *ptr) {
|
||||
//_delegates_write可能多线程同时操作
|
||||
std::lock_guard<std::mutex> lck(_mtx);
|
||||
_delegates_write.erase(ptr);
|
||||
_need_update = true;
|
||||
_delegates.erase(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入帧并派发
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override {
|
||||
if(_need_update){
|
||||
//发现代理列表发生变化了,这里同步一次
|
||||
std::lock_guard<std::mutex> lck(_mtx);
|
||||
_delegates_read = _delegates_write;
|
||||
_need_update = false;
|
||||
}
|
||||
|
||||
//_delegates_read能确保是单线程操作的
|
||||
bool ret = false;
|
||||
for (auto &pr : _delegates_read) {
|
||||
for (auto &pr : _delegates) {
|
||||
if (pr.second->inputFrame(frame)) {
|
||||
ret = true;
|
||||
}
|
||||
@ -360,13 +348,18 @@ public:
|
||||
* 返回代理个数
|
||||
*/
|
||||
size_t size() const {
|
||||
return _delegates_write.size();
|
||||
std::lock_guard<std::mutex> lck(_mtx);
|
||||
return _delegates.size();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
std::lock_guard<std::mutex> lck(_mtx);
|
||||
_delegates.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _mtx;
|
||||
std::map<void *,FrameWriterInterface::Ptr> _delegates_read;
|
||||
std::map<void *,FrameWriterInterface::Ptr> _delegates_write;
|
||||
bool _need_update = false;
|
||||
mutable std::mutex _mtx;
|
||||
std::map<void *, FrameWriterInterface::Ptr> _delegates;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user