Commit cb0e5c6c by ziyue

全面更新整理c sdk

parent 9736badc
......@@ -14,24 +14,21 @@
#include <stdint.h>
#include <stddef.h>
#if defined(_WIN32)
#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
#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
# define API_EXPORT
# define API_CALL
#endif
#ifdef __cplusplus
......
/*
* 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,68 +103,9 @@ 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,否则返回秒数
*/
API_EXPORT float API_CALL mk_player_duration(mk_player ctx);
......@@ -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,15 +66,27 @@ 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);
//TcpSession::safeShutdown()
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(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_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);
......@@ -61,7 +86,16 @@ typedef void (API_CALL *on_mk_async)(void *user_data);
* @param cb 回调函数
* @param user_data 用户数据指针
*/
API_EXPORT void API_CALL mk_async_do(mk_thread ctx,on_mk_async cb, void *user_data);
API_EXPORT void API_CALL mk_async_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);
/**
* 切换到事件线程并同步执行
......@@ -69,7 +103,7 @@ API_EXPORT void API_CALL mk_async_do(mk_thread ctx,on_mk_async cb, void *user_da
* @param cb 回调函数
* @param user_data 用户数据指针
*/
API_EXPORT void API_CALL mk_sync_do(mk_thread ctx,on_mk_async cb, void *user_data);
API_EXPORT void API_CALL mk_sync_do(mk_thread ctx, on_mk_async cb, void *user_data);
///////////////////////////////////////////定时器/////////////////////////////////////////////
typedef void* mk_timer;
......@@ -88,7 +122,7 @@ typedef uint64_t (API_CALL *on_mk_timer)(void *user_data);
* @param user_data 用户数据指针
* @return 定时器对象
*/
API_EXPORT mk_timer API_CALL mk_timer_create(mk_thread ctx,uint64_t delay_ms, on_mk_timer cb, void *user_data);
API_EXPORT mk_timer API_CALL mk_timer_create(mk_thread ctx, uint64_t delay_ms, on_mk_timer cb, void *user_data);
/**
* 销毁和取消定时器
......@@ -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
......
/*
* 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
\ No newline at end of file
/*
* 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
\ No newline at end of file
......@@ -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"
......
/*
* 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;
}
\ No newline at end of file
......@@ -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;
......
......@@ -47,51 +47,34 @@ public:
});
}
void unset(){
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){
lock_guard<recursive_mutex> lck(_mtx);
if(is_shutdown){
if (is_shutdown) {
//播放中断
if(_on_shutdown){
_on_shutdown(_on_shutdown_data,ex.getErrCode(),ex.what());
if (_on_shutdown) {
_on_shutdown(_on_shutdown_data, ex.getErrCode(), ex.what(), nullptr, 0);
}
return;
}
//播放结果
if(_on_play){
_on_play(_on_play_data,ex.getErrCode(),ex.what());
}
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;
if (_on_play) {
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;
}
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);
}
TcpSessionForC *session = (TcpSessionForC *)ctx;
session->SockSender::send(data,len);
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->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](){
std::weak_ptr<TcpSession> weak_session = ((TcpSessionForC *) ctx)->shared_from_this();
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);
if (session_session) {
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());
if (_events.on_mk_tcp_client_data) {
_events.on_mk_tcp_client_data(_client, (mk_buffer)&pBuf);
}
}
......@@ -246,26 +331,38 @@ 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);
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *)ctx;
(*client)->SockSender::send(data,len);
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)->send(*((Buffer::Ptr *) buffer));
}
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;
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 buf = BufferRaw::create();
buf->assign(data,len);
(*client)->async([weakClient,buf](){
auto ref = mk_buffer_ref(buffer);
(*client)->async([weakClient, ref]() {
auto strongClient = weakClient.lock();
if(strongClient){
strongClient->send(buf);
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){
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){
assert(ctx);
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *)ctx;
......
......@@ -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;
......@@ -107,4 +116,52 @@ API_EXPORT void API_CALL mk_timer_release(mk_timer ctx){
TimerForC::Ptr *obj = (TimerForC::Ptr *)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();
}
\ No newline at end of file
/*
* 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;
}
\ No newline at end of file
/*
* 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
\ No newline at end of file
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)
\ No newline at end of file
......@@ -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分帧器
......
/*
* 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;
}
\ No newline at end of file
/*
* 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;
}
\ No newline at end of file
......@@ -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
......@@ -179,20 +136,14 @@ int main(int argc, char *argv[]){
mk_rtsp_server_start(554, 0);
mk_rtmp_server_start(1935, 0);
Context *ctx = (Context *)malloc(sizeof(Context));
Context *ctx = (Context *) malloc(sizeof(Context));
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");
int i = 10 * 60;
while(--i){
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
context_start(ctx, argv[1], argv[2]);
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;
}
\ No newline at end of file
......@@ -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;
}
\ No newline at end of file
......@@ -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可能多线程同时操作
void addDelegate(const FrameWriterInterface::Ptr &delegate) {
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可能多线程同时操作
void delDelegate(FrameWriterInterface *ptr) {
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 inputFrame(const Frame::Ptr &frame) override {
std::lock_guard<std::mutex> lck(_mtx);
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;
};
/**
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论