player增加speed,pause扩展,seek支持秒级定位,MP4按时间戳生成文件

This commit is contained in:
baiyfcu 2021-08-09 18:28:43 +08:00
parent 9e5d325e43
commit 0ed902509a
25 changed files with 455 additions and 52 deletions

1
.gitignore vendored
View File

@ -35,6 +35,7 @@
/cmake-build-release/ /cmake-build-release/
/linux/ /linux/
/.vs/ /.vs/
/.vscode/
/.idea/ /.idea/
/c_wrapper/.idea/ /c_wrapper/.idea/
/release/ /release/

View File

@ -17,16 +17,21 @@ endif ()
#binlib #binlib
set(RELEASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/release) set(RELEASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/release)
if(CMAKE_CL_64)
set(CL_32_64 64)
else(CMAKE_CL_64)
set(CL_32_64 32)
endif(CMAKE_CL_64)
if (CMAKE_SYSTEM_NAME MATCHES "Linux") if (CMAKE_SYSTEM_NAME MATCHES "Linux")
SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/linux/${BuildType}) SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/linux${CL_32_64}/${BuildType})
SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/linux/${BuildType}) SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/linux${CL_32_64}/${BuildType})
add_compile_options(-fPIC -Wall -Wno-unused-variable -Wno-unused-value) add_compile_options(-fPIC -Wall -Wno-unused-variable -Wno-unused-value)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/windows/${BuildType}) SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${BuildType})
SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/windows/${BuildType}) SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${BuildType})
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/mac/${BuildType}) SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/mac${CL_32_64}/${BuildType})
SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/mac/${BuildType}) SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/mac${CL_32_64/${BuildType})
add_compile_options(-Wall -Wno-unused-variable -Wno-unused-value) add_compile_options(-Wall -Wno-unused-variable -Wno-unused-value)
endif () endif ()
@ -57,6 +62,22 @@ option(ENABLE_MEM_DEBUG "Enable Memory Debug" false)
option(ENABLE_ASAN "Enable Address Sanitize" false) option(ENABLE_ASAN "Enable Address Sanitize" false)
option(ENABLE_WEBRTC "Enable WebRTC" false) option(ENABLE_WEBRTC "Enable WebRTC" false)
option(ENABLE_PLAYER "Enable Player" true) option(ENABLE_PLAYER "Enable Player" true)
option(ENABLE_MsvcMT "Enable MSVC Mt/Mtd lib" true)
if (ENABLE_STATIC AND MSVC)
set(CompilerFlags
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
)
foreach(CompilerFlag ${CompilerFlags})
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()
endif()
# git # git
set(COMMIT_HASH "Git_NotFound_Unkown_commit") set(COMMIT_HASH "Git_NotFound_Unkown_commit")

View File

@ -142,6 +142,19 @@ API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close c
*/ */
typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms); typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms);
/**
* pause请求时触发该回调
* @param user_data ,mk_media_set_on_pause设置
*/
typedef int(API_CALL* on_mk_media_pause)(void* user_data);
/**
* speed请求时触发该回调
* @param user_data ,mk_media_set_on_pause设置
* @param speed 0.5 1.0 2.0
*/
typedef int(API_CALL* on_mk_media_speed)(void* user_data, float speed);
/** /**
* seek请求事件 * seek请求事件
* @param ctx * @param ctx
@ -150,6 +163,22 @@ typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms);
*/ */
API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data); API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data);
/**
* pause请求事件
* @param ctx
* @param cb
* @param user_data
*/
API_EXPORT void API_CALL mk_media_set_on_pause(mk_media ctx, on_mk_media_pause cb, void* user_data);
/**
* pause请求事件
* @param ctx
* @param cb
* @param user_data
*/
API_EXPORT void API_CALL mk_media_set_on_speed(mk_media ctx, on_mk_media_speed cb, void* user_data);
/** /**
* *
* @param ctx * @param ctx

View File

@ -73,6 +73,13 @@ API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url);
*/ */
API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause); API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause);
/**
*
* @param ctx
* @param speed 0.5 1.0 2.0
*/
API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed);
/** /**
* *
* @param ctx * @param ctx
@ -80,6 +87,13 @@ API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause);
*/ */
API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress); API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress);
/**
*
* @param ctx
* @param seekPos
*/
API_EXPORT void API_CALL mk_player_seektoByPos(mk_player ctx, int seekPos);
/** /**
* *
* @param ctx * @param ctx
@ -112,6 +126,15 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb
*/ */
API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx); API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx);
/**
* codec_id, vendor类型, codec_id -1 0H2641H2652AAC 3.G711A 4.G711U
* @param ctx
* @param vendor H264另外还有厂家类型
* @param head SDK头数据
* @param head SDK头数据长度
*/
API_EXPORT int API_CALL mk_player_video_codecId_vendor_head(mk_player ctx, char* vendor, char* head, int* headLen);
/** /**
* *
*/ */
@ -154,10 +177,15 @@ API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx);
API_EXPORT float API_CALL mk_player_duration(mk_player ctx); API_EXPORT float API_CALL mk_player_duration(mk_player ctx);
/** /**
* 0.01.0 * 0.01.0
*/ */
API_EXPORT float API_CALL mk_player_progress(mk_player ctx); API_EXPORT float API_CALL mk_player_progress(mk_player ctx);
/**
*
*/
API_EXPORT int API_CALL mk_player_progress_pos(mk_player ctx);
/** /**
* rtsp时有效 * rtsp时有效
* @param ctx * @param ctx

View File

@ -43,6 +43,16 @@ public:
_on_seek_data = user_data; _on_seek_data = user_data;
} }
void setOnPause(on_mk_media_pause cb, void* user_data) {
_on_pause = cb;
_on_pause_data = user_data;
}
void setOnSpeed(on_mk_media_speed cb, void* user_data) {
_on_speed = cb;
_on_speed_data = user_data;
}
void setOnRegist(on_mk_media_source_regist cb, void *user_data){ void setOnRegist(on_mk_media_source_regist cb, void *user_data){
_on_regist = cb; _on_regist = cb;
_on_regist_data = user_data; _on_regist_data = user_data;
@ -72,6 +82,23 @@ protected:
} }
return _on_seek(_on_seek_data,ui32Stamp); return _on_seek(_on_seek_data,ui32Stamp);
} }
// 通知暂停
bool pause(MediaSource &sender) override {
if (!_on_pause)
{
return false;
}
return _on_pause(_on_pause_data);
}
//通知倍数播放
bool speed(MediaSource& sender, float speed) override {
if (!_on_speed)
{
return false;
}
return _on_speed(_on_pause_data, speed);
}
// 观看总人数 // 观看总人数
int totalReaderCount(MediaSource &sender) override{ int totalReaderCount(MediaSource &sender) override{
return _channel->totalReaderCount(); return _channel->totalReaderCount();
@ -87,8 +114,12 @@ private:
DevChannel::Ptr _channel; DevChannel::Ptr _channel;
on_mk_media_close _on_close = nullptr; on_mk_media_close _on_close = nullptr;
on_mk_media_seek _on_seek = nullptr; on_mk_media_seek _on_seek = nullptr;
on_mk_media_pause _on_pause = nullptr;
on_mk_media_speed _on_speed = nullptr;
on_mk_media_source_regist _on_regist = nullptr; on_mk_media_source_regist _on_regist = nullptr;
void *_on_seek_data; void* _on_seek_data;
void* _on_pause_data;
void* _on_speed_data;
void *_on_close_data; void *_on_close_data;
void *_on_regist_data; void *_on_regist_data;
}; };
@ -105,6 +136,20 @@ API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb,
(*obj)->setOnSeek(cb, user_data); (*obj)->setOnSeek(cb, user_data);
} }
API_EXPORT void API_CALL mk_media_set_on_pause(mk_media ctx, on_mk_media_pause cb, void* user_data)
{
assert(ctx);
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
(*obj)->setOnPause(cb, user_data);
}
API_EXPORT void API_CALL mk_media_set_on_speed(mk_media ctx, on_mk_media_speed cb, void* user_data)
{
assert(ctx);
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
(*obj)->setOnSpeed(cb, user_data);
}
API_EXPORT void API_CALL mk_media_set_on_regist(mk_media ctx, on_mk_media_source_regist cb, void *user_data){ API_EXPORT void API_CALL mk_media_set_on_regist(mk_media ctx, on_mk_media_source_regist cb, void *user_data){
assert(ctx); assert(ctx);
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;

View File

@ -11,6 +11,8 @@
#include "mk_player.h" #include "mk_player.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Player/MediaPlayer.h" #include "Player/MediaPlayer.h"
#include "Extension/H264.h"
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
using namespace mediakit; using namespace mediakit;
@ -167,6 +169,16 @@ API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) {
}); });
} }
API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed) {
assert(ctx);
MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx);
auto player = obj.getPlayer();
player->getPoller()->async([speed, player]() {
//切换线程后再操作
player->speed(speed);
});
}
API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) {
assert(ctx); assert(ctx);
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
@ -177,6 +189,16 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) {
}); });
} }
API_EXPORT void API_CALL mk_player_seektoByPos(mk_player ctx, int seekPos){
assert(ctx);
MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx);
auto player = obj.getPlayer();
player->getPoller()->async([seekPos, player]() {
//切换线程后再操作
player->seekTo((uint32_t)seekPos);
});
}
static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) { static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) {
assert(ctx); assert(ctx);
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
@ -204,6 +226,32 @@ API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx){
return track ? track->getCodecId() : CodecInvalid; return track ? track->getCodecId() : CodecInvalid;
} }
API_EXPORT int API_CALL mk_player_video_codecId_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) { API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);
@ -265,6 +313,14 @@ API_EXPORT float API_CALL mk_player_progress(mk_player ctx) {
return obj->getProgress(); return obj->getProgress();
} }
API_EXPORT int API_CALL mk_player_progress_pos(mk_player ctx)
{
assert(ctx);
MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx);
return obj->getProgressPos();
}
API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) { API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) {
assert(ctx); assert(ctx);
MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx);

View File

@ -118,13 +118,15 @@ static HttpApi toApi(const function<void(API_ARGS_JSON_ASYNC)> &cb) {
Json::Reader reader; Json::Reader reader;
reader.parse(parser.Content(), in); reader.parse(parser.Content(), in);
cb(sender, parser.getHeader(), headerOut, in, out, invoker); //参数解析成map
auto urlArgs = getAllArgs(parser);
cb(sender, parser.getHeader(), headerOut, in, urlArgs, out, invoker);
}; };
} }
static HttpApi toApi(const function<void(API_ARGS_JSON)> &cb) { static HttpApi toApi(const function<void(API_ARGS_JSON)> &cb) {
return toApi([cb](API_ARGS_JSON_ASYNC) { return toApi([cb](API_ARGS_JSON_ASYNC) {
cb(API_ARGS_VALUE); cb(API_ARGS_JSON_VALUE);
invoker(200, headerOut, val.toStyledString()); invoker(200, headerOut, val.toStyledString());
}); });
} }
@ -228,18 +230,19 @@ static inline void addHttpListener(){
size = body->remainSize(); size = body->remainSize();
} }
const std::string& content = parser.Content();
if (size && size < 4 * 1024) { if (size && size < 4 * 1024) {
string contentOut = body->readData(size)->toString(); string contentOut = body->readData(size)->toString();
DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n" DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
<< "# content:\r\n" << parser.Content() << "\r\n" << "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n"
<< "# response:\r\n" << "# response:\r\n"
<< contentOut << "\r\n"; << contentOut << "\r\n";
invoker(code, headerOut, contentOut); invoker(code, headerOut, contentOut);
} else { } else {
DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n" DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
<< "# content:\r\n" << parser.Content() << "\r\n" << "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n"
<< "# response size:" << "# response size:"
<< size << "\r\n"; << size << "\r\n";
invoker(code, headerOut, body); invoker(code, headerOut, body);
} }
}; };
@ -276,8 +279,8 @@ static recursive_mutex s_ffmpegMapMtx;
#if defined(ENABLE_RTPPROXY) #if defined(ENABLE_RTPPROXY)
//rtp服务器列表 //rtp服务器列表
static unordered_map<string, RtpServer::Ptr> s_rtpServerMap; /*static*/ unordered_map<string, RtpServer::Ptr> s_rtpServerMap;
static recursive_mutex s_rtpServerMapMtx; /*static*/ recursive_mutex s_rtpServerMapMtx;
#endif #endif
static inline string getProxyKey(const string &vhost, const string &app, const string &stream) { static inline string getProxyKey(const string &vhost, const string &app, const string &stream) {
@ -932,21 +935,56 @@ void installWebApi() {
api_regist("/index/api/startSendRtp",[](API_ARGS_MAP_ASYNC){ api_regist("/index/api/startSendRtp",[](API_ARGS_MAP_ASYNC){
CHECK_SECRET(); CHECK_SECRET();
CHECK_ARGS("vhost", "app", "stream", "ssrc", "dst_url", "dst_port", "is_udp"); CHECK_ARGS("vhost", "app", "stream", "ssrc", "dst_url", "dst_port", "is_udp");
bool isAsync = false;
if (checkArgs(allArgs, "is_async"))
isAsync = allArgs["is_async"];
if (isAsync)
{
MediaInfo info = {};
info._vhost = allArgs["vhost"];
info._app = allArgs["app"];
info._streamid = allArgs["stream"];
info._schema = RTSP_SCHEMA;
auto session = static_cast<TcpSession*>(&sender);
auto session_ptr = session->shared_from_this();
auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]); MediaSource::findAsync(info, session_ptr, [=](const MediaSource::Ptr& src_in) mutable {
if (!src) { if (!src_in) {
throw ApiRetException("该媒体流不存在", API::OtherFailed); val["code"] = API::OtherFailed;
val["msg"] = "该媒体流不存在";
invoker(200, headerOut, val.toStyledString());
return;
}
auto src = dynamic_pointer_cast<RtspMediaSource>(src_in);
//src_port为空时则随机本地端口
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable {
if (ex) {
val["code"] = API::OtherFailed;
val["msg"] = ex.what();
}
val["local_port"] = local_port;
invoker(200, headerOut, val.toStyledString());
});
});
}
else
{
auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]);
if (!src) {
throw ApiRetException("该媒体流不存在", API::OtherFailed);
}
//src_port为空时则随机本地端口
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable {
if (ex) {
val["code"] = API::OtherFailed;
val["msg"] = ex.what();
}
val["local_port"] = local_port;
invoker(200, headerOut, val.toStyledString());
});
} }
//src_port为空时则随机本地端口
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException &ex) mutable{
if (ex) {
val["code"] = API::OtherFailed;
val["msg"] = ex.what();
}
val["local_port"] = local_port;
invoker(200, headerOut, val.toStyledString());
});
}); });
api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){ api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){

View File

@ -83,11 +83,12 @@ using ApiArgsType = map<string, variant, StrCaseCompare>;
#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val #define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val
#define API_ARGS_MAP_ASYNC API_ARGS_MAP, const HttpSession::HttpResponseInvoker &invoker #define API_ARGS_MAP_ASYNC API_ARGS_MAP, const HttpSession::HttpResponseInvoker &invoker
#define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, Json::Value &allArgs, Json::Value &val #define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, Json::Value &bodyArgs, ApiArgsType &allArgs, Json::Value &val
#define API_ARGS_JSON_ASYNC API_ARGS_JSON, const HttpSession::HttpResponseInvoker &invoker #define API_ARGS_JSON_ASYNC API_ARGS_JSON, const HttpSession::HttpResponseInvoker &invoker
#define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, const Parser &allArgs, Json::Value &val #define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, const Parser &allArgs, Json::Value &val
#define API_ARGS_STRING_ASYNC API_ARGS_STRING, const HttpSession::HttpResponseInvoker &invoker #define API_ARGS_STRING_ASYNC API_ARGS_STRING, const HttpSession::HttpResponseInvoker &invoker
#define API_ARGS_VALUE sender, headerIn, headerOut, allArgs, val #define API_ARGS_VALUE sender, headerIn, headerOut, allArgs, val
#define API_ARGS_JSON_VALUE sender, headerIn, headerOut, bodyArgs, allArgs, val
//注册http请求参数是map<string, variant, StrCaseCompare>类型的http api //注册http请求参数是map<string, variant, StrCaseCompare>类型的http api
void api_regist(const string &api_path, const function<void(API_ARGS_MAP)> &func); void api_regist(const string &api_path, const function<void(API_ARGS_MAP)> &func);

View File

@ -157,6 +157,24 @@ bool MediaSource::seekTo(uint32_t stamp) {
return listener->seekTo(*this, stamp); return listener->seekTo(*this, stamp);
} }
bool MediaSource::pause()
{
auto listener = _listener.lock();
if (!listener) {
return false;
}
return listener->pause(*this);
}
bool MediaSource::speed(float speed)
{
auto listener = _listener.lock();
if (!listener) {
return false;
}
return listener->speed(*this, speed);
}
bool MediaSource::close(bool force) { bool MediaSource::close(bool force) {
auto listener = _listener.lock(); auto listener = _listener.lock();
if(!listener){ if(!listener){
@ -588,6 +606,24 @@ bool MediaSourceEventInterceptor::seekTo(MediaSource &sender, uint32_t stamp) {
return listener->seekTo(sender, stamp); return listener->seekTo(sender, stamp);
} }
bool MediaSourceEventInterceptor::pause(MediaSource& sender)
{
auto listener = _listener.lock();
if (!listener) {
return false;
}
return listener->pause(sender);
}
bool MediaSourceEventInterceptor::speed(MediaSource& sender, float speed)
{
auto listener = _listener.lock();
if (!listener) {
return false;
}
return listener->speed(sender, speed);
}
bool MediaSourceEventInterceptor::close(MediaSource &sender, bool force) { bool MediaSourceEventInterceptor::close(MediaSource &sender, bool force) {
auto listener = _listener.lock(); auto listener = _listener.lock();
if (!listener) { if (!listener) {

View File

@ -67,6 +67,10 @@ public:
// 通知拖动进度条 // 通知拖动进度条
virtual bool seekTo(MediaSource &sender, uint32_t stamp) { return false; } virtual bool seekTo(MediaSource &sender, uint32_t stamp) { return false; }
// 通知暂停
virtual bool pause(MediaSource& sender) { return false; }
// 通知倍数
virtual bool speed(MediaSource& sender, float speed) { return false; }
// 通知其停止产生流 // 通知其停止产生流
virtual bool close(MediaSource &sender, bool force) { return false; } virtual bool close(MediaSource &sender, bool force) { return false; }
// 获取观看总人数 // 获取观看总人数
@ -106,6 +110,8 @@ public:
std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override; std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override;
bool seekTo(MediaSource &sender, uint32_t stamp) override; bool seekTo(MediaSource &sender, uint32_t stamp) override;
bool pause(MediaSource& sender) override;
bool speed(MediaSource& sender, float speed) override;
bool close(MediaSource &sender, bool force) override; bool close(MediaSource &sender, bool force) override;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
void onReaderChanged(MediaSource &sender, int size) override; void onReaderChanged(MediaSource &sender, int size) override;
@ -249,6 +255,11 @@ public:
// 拖动进度条 // 拖动进度条
bool seekTo(uint32_t stamp); bool seekTo(uint32_t stamp);
//暂停
bool pause();
//倍数播放
bool speed(float speed);
// 关闭该流 // 关闭该流
bool close(bool force); bool close(bool force);
// 该流观看人数变化 // 该流观看人数变化

View File

@ -30,9 +30,12 @@ public:
void setOnResult(const onDownloadResult &cb){ void setOnResult(const onDownloadResult &cb){
_onResult = cb; _onResult = cb;
} }
protected:
void onResponseBody(const char *buf, size_t size, size_t recvedSize, size_t totalSize) override;
private: private:
ssize_t onResponseHeader(const string &status, const HttpHeader &headers) override; ssize_t onResponseHeader(const string &status, const HttpHeader &headers) override;
void onResponseBody(const char *buf, size_t size, size_t recvedSize, size_t totalSize) override;
void onResponseCompleted() override; void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override; void onDisconnect(const SockException &ex) override;
void closeFile(); void closeFile();

View File

@ -64,6 +64,13 @@ void MediaPlayer::pause(bool pause) {
} }
} }
void MediaPlayer::speed(float speed)
{
if (_delegate) {
_delegate->speed(speed);
}
}
void MediaPlayer::teardown() { void MediaPlayer::teardown() {
if (_delegate) { if (_delegate) {
_delegate->teardown(); _delegate->teardown();

View File

@ -29,6 +29,7 @@ public:
virtual ~MediaPlayer(); virtual ~MediaPlayer();
void play(const string &url) override; void play(const string &url) override;
void pause(bool pause) override; void pause(bool pause) override;
void speed(float speed)override;
void teardown() override; void teardown() override;
EventPoller::Ptr getPoller(); EventPoller::Ptr getPoller();
void setOnCreateSocket(Socket::onCreateSocket cb); void setOnCreateSocket(Socket::onCreateSocket cb);

View File

@ -65,6 +65,12 @@ public:
*/ */
virtual void pause(bool bPause) {} virtual void pause(bool bPause) {}
/**
*
* @param speed 1.0 2.0 0.5
*/
virtual void speed(float speed) {}
/** /**
* *
*/ */
@ -94,12 +100,24 @@ public:
*/ */
virtual float getProgress() const { return 0;} virtual float getProgress() const { return 0;}
/**
* pos
* @return
*/
virtual uint32_t getProgressPos() const { return 0; }
/** /**
* *
* @param fProgress 0.0 ~ 1.0 * @param fProgress 0.0 ~ 1.0
*/ */
virtual void seekTo(float fProgress) {} virtual void seekTo(float fProgress) {}
/**
*
* @param seekPos
*/
virtual void seekTo(uint32_t seekPos) {}
/** /**
* MediaSourcertsp/rtmp代理 * MediaSourcertsp/rtmp代理
* @param src * @param src
@ -175,6 +193,12 @@ public:
} }
return Parent::getProgress(); return Parent::getProgress();
} }
uint32_t getProgressPos() const override {
if (_delegate) {
return _delegate->getProgressPos();
}
return Parent::getProgressPos();
}
void seekTo(float fProgress) override{ void seekTo(float fProgress) override{
if (_delegate) { if (_delegate) {
return _delegate->seekTo(fProgress); return _delegate->seekTo(fProgress);
@ -182,6 +206,13 @@ public:
return Parent::seekTo(fProgress); return Parent::seekTo(fProgress);
} }
void seekTo(uint32_t seekPos) override {
if (_delegate) {
return _delegate->seekTo(seekPos);
}
return Parent::seekTo(seekPos);
}
void setMediaSource(const MediaSource::Ptr & src) override { void setMediaSource(const MediaSource::Ptr & src) override {
if (_delegate) { if (_delegate) {
_delegate->setMediaSource(src); _delegate->setMediaSource(src);

View File

@ -107,12 +107,17 @@ void MP4Recorder::closeFile() {
} }
void MP4Recorder::inputFrame(const Frame::Ptr &frame) { void MP4Recorder::inputFrame(const Frame::Ptr &frame) {
if(!_muxer || ((_createFileTicker.elapsedTime() > _max_second * 1000) && if (_baseSec == 0)
_baseSec = frame->dts();
auto dis = frame->dts() - _baseSec;
if(!_muxer || ((dis > _max_second * 1000) &&
(!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){
//成立条件 //成立条件
//1、_muxer为空 //1、_muxer为空
//2、到了切片时间并且只有音频 //2、到了切片时间并且只有音频
//3、到了切片时间有视频并且遇到视频的关键帧 //3、到了切片时间有视频并且遇到视频的关键帧
DebugL << "create file dts:" << frame->dts() << " baseSec:" << _baseSec;
_baseSec = 0;
createFile(); createFile();
} }

View File

@ -65,6 +65,8 @@ private:
RecordInfo _info; RecordInfo _info;
MP4Muxer::Ptr _muxer; MP4Muxer::Ptr _muxer;
list<Track::Ptr> _tracks; list<Track::Ptr> _tracks;
uint64_t _baseSec = 0;
}; };
#endif ///ENABLE_MP4 #endif ///ENABLE_MP4

View File

@ -171,6 +171,11 @@ void RtmpPlayer::pause(bool bPause) {
send_pause(bPause); send_pause(bPause);
} }
void RtmpPlayer::speed(float speed)
{
//todo
}
inline void RtmpPlayer::send_connect() { inline void RtmpPlayer::send_connect() {
AMFValue obj(AMF_OBJECT); AMFValue obj(AMF_OBJECT);
obj.set("app", _app); obj.set("app", _app);

View File

@ -38,6 +38,7 @@ public:
void play(const string &strUrl) override; void play(const string &strUrl) override;
void pause(bool bPause) override; void pause(bool bPause) override;
void speed(float speed)override;
void teardown() override; void teardown() override;
protected: protected:

View File

@ -46,6 +46,11 @@ public:
seekToMilliSecond((uint32_t)(fProgress * getDuration() * 1000)); seekToMilliSecond((uint32_t)(fProgress * getDuration() * 1000));
} }
void seekTo(uint32_t seekPos) override {
uint32_t pos = MAX(float(0), MIN(seekPos, getDuration()))*1000;
seekToMilliSecond(pos);
}
void play(const string &strUrl) override { void play(const string &strUrl) override {
PlayerImp<RtmpPlayer, RtmpDemuxer>::play(strUrl); PlayerImp<RtmpPlayer, RtmpDemuxer>::play(strUrl);
} }

View File

@ -412,6 +412,36 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) {
//streamBegin //streamBegin
sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, STREAM_MEDIA); sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, STREAM_MEDIA);
_paused = paused; _paused = paused;
auto stongSrc = _player_src.lock();
if (stongSrc) {
if (_paused)
stongSrc->pause();
else
stongSrc->seekTo(-1);
}
}
void RtmpSession::onCmd_playCtrl(AMFDecoder& dec)
{
dec.load<AMFValue>();
auto ctrlObj = dec.load<AMFValue>();
int ctrlType = ctrlObj["ctrlType"].as_integer();
float speed = ctrlObj["speed"].as_number();
AMFValue status(AMF_OBJECT);
status.set("level", "status");
status.set("code", "NetStream.Speed.Notify");
status.set("description", "Speeding");
sendReply("onStatus", nullptr, status);
//streamBegin
sendUserControl(CONTROL_STREAM_EOF, STREAM_MEDIA);
auto stongSrc = _player_src.lock();
if (stongSrc) {
stongSrc->speed(speed);
}
} }
void RtmpSession::setMetaData(AMFDecoder &dec) { void RtmpSession::setMetaData(AMFDecoder &dec) {
@ -434,6 +464,7 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) {
s_cmd_functions.emplace("play2", &RtmpSession::onCmd_play2); s_cmd_functions.emplace("play2", &RtmpSession::onCmd_play2);
s_cmd_functions.emplace("seek", &RtmpSession::onCmd_seek); s_cmd_functions.emplace("seek", &RtmpSession::onCmd_seek);
s_cmd_functions.emplace("pause", &RtmpSession::onCmd_pause); s_cmd_functions.emplace("pause", &RtmpSession::onCmd_pause);
s_cmd_functions.emplace("onPlayCtrl", &RtmpSession::onCmd_playCtrl);
}); });
std::string method = dec.load<std::string>(); std::string method = dec.load<std::string>();

View File

@ -53,6 +53,7 @@ private:
void onCmd_seek(AMFDecoder &dec); void onCmd_seek(AMFDecoder &dec);
void onCmd_pause(AMFDecoder &dec); void onCmd_pause(AMFDecoder &dec);
void onCmd_playCtrl(AMFDecoder& dec);
void setMetaData(AMFDecoder &dec); void setMetaData(AMFDecoder &dec);
void onSendMedia(const RtmpPacket::Ptr &pkt); void onSendMedia(const RtmpPacket::Ptr &pkt);

View File

@ -25,7 +25,8 @@ namespace mediakit {
enum PlayType { enum PlayType {
type_play = 0, type_play = 0,
type_pause, type_pause,
type_seek type_seek,
type_speed
}; };
RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){ RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){
@ -414,8 +415,13 @@ void RtspPlayer::sendPause(int type , uint32_t seekMS){
} }
} }
void RtspPlayer::pause(bool pause_flag) { void RtspPlayer::pause(bool bPause) {
sendPause(pause_flag ? type_pause : type_seek, getProgressMilliSecond()); sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond());
}
void RtspPlayer::speed(float speed)
{
sendRtspRequest("PLAY", _content_base, { "Scale",StrPrinter << speed });
} }
void RtspPlayer::handleResPAUSE(const Parser& parser,int type) { void RtspPlayer::handleResPAUSE(const Parser& parser,int type) {

View File

@ -41,7 +41,8 @@ public:
~RtspPlayer() override; ~RtspPlayer() override;
void play(const string &strUrl) override; void play(const string &strUrl) override;
void pause(bool pause_flag) override; void pause(bool bPause) override;
void speed(float speed)override;
void teardown() override; void teardown() override;
float getPacketLossRate(TrackType type) const override; float getPacketLossRate(TrackType type) const override;

View File

@ -42,11 +42,24 @@ public:
} }
void seekTo(float fProgress) override { uint32_t getProgressPos() const override {
fProgress = MAX(float(0), MIN(fProgress, float(1.0))); if (getDuration() > 0) {
return getProgressMilliSecond();
}
return PlayerBase::getProgressPos();
};
void seekTo(float fProgress) override{
fProgress = MAX(float(0),MIN(fProgress,float(1.0)));
seekToMilliSecond((uint32_t)(fProgress * getDuration() * 1000)); seekToMilliSecond((uint32_t)(fProgress * getDuration() * 1000));
} }
void seekTo(uint32_t seekPos) override {
uint32_t pos = MAX(float(0), MIN(seekPos, getDuration()))*1000;
seekToMilliSecond(pos);
}
private: private:
//派生类回调函数 //派生类回调函数
bool onCheckSDP(const string &sdp) override { bool onCheckSDP(const string &sdp) override {

View File

@ -774,21 +774,36 @@ void RtspSession::handleReq_Play(const Parser &parser) {
} }
bool useGOP = true; bool useGOP = true;
_enable_send_rtp = false; //_enable_send_rtp = false;
float iStartTime = 0; float iStartTime = 0;
auto strRange = parser["Range"]; auto strRange = parser["Range"];
if (strRange.size()) { auto strScale = parser["Scale"];
//这个是seek操作 if (strScale.size() == 0)
auto strStart = FindField(strRange.data(), "npt=", "-"); {
if (strStart == "now") {
strStart = "0"; if (strRange.size()) {
//这个是seek操作
auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") {
strStart = "0";
}
iStartTime = 1000 * (float)atof(strStart.data());
InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
useGOP = !play_src->seekTo((uint32_t)iStartTime);
} }
iStartTime = 1000 * (float)atof(strStart.data()); else if (play_src->totalReaderCount() == 0) {
InfoP(this) << "rtsp seekTo(ms):" << iStartTime; //第一个消费者
useGOP = !play_src->seekTo((uint32_t)iStartTime); play_src->seekTo(0);
} else if (play_src->totalReaderCount() == 0) { }
//第一个消费者 else if (play_src->totalReaderCount() > 0)
play_src->seekTo(0); {
_enable_send_rtp = true;
play_src->seekTo(-1);
}
}
else
{
play_src->speed(atof(strScale.data()));
} }
_StrPrinter rtp_info; _StrPrinter rtp_info;
@ -845,7 +860,17 @@ void RtspSession::handleReq_Pause(const Parser &parser) {
} }
sendRtspResponse("200 OK"); sendRtspResponse("200 OK");
_enable_send_rtp = false;
auto play_src = _play_src.lock();
if (!play_src) {
send_StreamNotFound();
shutdown(SockException(Err_shutdown, "rtsp stream released"));
return;
}
play_src->pause();
//_enable_send_rtp = false;
} }
void RtspSession::handleReq_Teardown(const Parser &parser) { void RtspSession::handleReq_Teardown(const Parser &parser) {