diff --git a/postman/ZLMediaKit.postman_collection.json b/postman/ZLMediaKit.postman_collection.json index 3b1d5a43..48d93811 100644 --- a/postman/ZLMediaKit.postman_collection.json +++ b/postman/ZLMediaKit.postman_collection.json @@ -428,7 +428,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{ZLMediaKit_URL}}/index/api/addStreamProxy?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=live&stream=test&url=rtmp://live.hkstv.hk.lxdns.com/live/hks2&enable_rtsp=1&enable_rtmp=1", + "raw": "{{ZLMediaKit_URL}}/index/api/addStreamProxy?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=live&stream=test&url=rtmp://live.hkstv.hk.lxdns.com/live/hks2", "host": [ "{{ZLMediaKit_URL}}" ], @@ -523,7 +523,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{ZLMediaKit_URL}}/index/api/addFFmpegSource?secret={{ZLMediaKit_secret}}&src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://10.8.9.115:8554/live/hks2&timeout_ms=10000", + "raw": "{{ZLMediaKit_URL}}/index/api/addFFmpegSource?secret={{ZLMediaKit_secret}}&src_url=http://hefeng.live.tempsource.cjyun.org/videotmp/s10100-hftv.m3u8&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000&enable_hls=0&enable_mp4=0", "host": [ "{{ZLMediaKit_URL}}" ], @@ -540,7 +540,7 @@ }, { "key": "src_url", - "value": "http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8", + "value": "http://hefeng.live.tempsource.cjyun.org/videotmp/s10100-hftv.m3u8", "description": "FFmpeg拉流地址,支持任意协议或格式(只要FFmpeg支持即可)" }, { @@ -552,6 +552,16 @@ "key": "timeout_ms", "value": "10000", "description": "FFmpeg推流成功超时时间,单位毫秒" + }, + { + "key": "enable_hls", + "value": "0", + "description": "是否开启hls录制" + }, + { + "key": "enable_mp4", + "value": "0", + "description": "是否开启mp4录制" } ] } diff --git a/server/FFmpegSource.cpp b/server/FFmpegSource.cpp index 6ae12e85..62e0e404 100644 --- a/server/FFmpegSource.cpp +++ b/server/FFmpegSource.cpp @@ -59,6 +59,11 @@ static bool is_local_ip(const string &ip){ return false; } +void FFmpegSource::setupRecord(bool enable_hls, bool enable_mp4){ + _enable_hls = enable_hls; + _enable_mp4 = enable_mp4; +} + void FFmpegSource::play(const string &src_url,const string &dst_url,int timeout_ms,const onPlay &cb) { GET_CONFIG(string,ffmpeg_bin,FFmpeg::kBin); GET_CONFIG(string,ffmpeg_cmd,FFmpeg::kCmd); @@ -263,6 +268,12 @@ void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) { //防止多次进入onGetMediaSource函数导致无限递归调用的bug setDelegate(listener); src->setListener(shared_from_this()); + if (_enable_hls) { + src->setupRecord(Recorder::type_hls, true, ""); + } + if (_enable_mp4) { + src->setupRecord(Recorder::type_mp4, true, ""); + } } } diff --git a/server/FFmpegSource.h b/server/FFmpegSource.h index 1b9c1e9f..48c21ae7 100644 --- a/server/FFmpegSource.h +++ b/server/FFmpegSource.h @@ -46,13 +46,29 @@ public: typedef function onPlay; FFmpegSource(); - virtual ~FFmpegSource(); + ~FFmpegSource(); + /** * 设置主动关闭回调 - * @param cb */ void setOnClose(const function &cb); - void play(const string &src_url,const string &dst_url,int timeout_ms,const onPlay &cb); + + /** + * 开始播放url + * @param src_url FFmpeg拉流地址 + * @param dst_url FFmpeg推流地址 + * @param timeout_ms 等待结果超时时间,单位毫秒 + * @param cb 成功与否回调 + */ + void play(const string &src_url, const string &dst_url, int timeout_ms, const onPlay &cb); + + /** + * 设置录制 + * @param enable_hls 是否开启hls直播或录制 + * @param enable_mp4 是否录制mp4 + */ + void setupRecord(bool enable_hls, bool enable_mp4); + private: void findAsync(int maxWaitMS ,const function &cb); void startTimer(int timeout_ms); @@ -69,6 +85,8 @@ private: std::shared_ptr getOriginSock(MediaSource &sender) const override; private: + bool _enable_hls = false; + bool _enable_mp4 = false; Process _process; Timer::Ptr _timer; EventPoller::Ptr _poller; diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 61ee2221..768b2e64 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -694,28 +694,31 @@ void installWebApi() { static auto addFFmpegSource = [](const string &src_url, const string &dst_url, int timeout_ms, - const function &cb){ + bool enable_hls, + bool enable_mp4, + const function &cb) { auto key = MD5(dst_url).hexdigest(); lock_guard lck(s_ffmpegMapMtx); - if(s_ffmpegMap.find(key) != s_ffmpegMap.end()){ + if (s_ffmpegMap.find(key) != s_ffmpegMap.end()) { //已经在拉流了 - cb(SockException(Err_success),key); + cb(SockException(Err_success), key); return; } FFmpegSource::Ptr ffmpeg = std::make_shared(); s_ffmpegMap[key] = ffmpeg; - ffmpeg->setOnClose([key](){ + ffmpeg->setOnClose([key]() { lock_guard lck(s_ffmpegMapMtx); s_ffmpegMap.erase(key); }); - ffmpeg->play(src_url, dst_url,timeout_ms,[cb , key](const SockException &ex){ - if(ex){ + ffmpeg->setupRecord(enable_hls, enable_mp4); + ffmpeg->play(src_url, dst_url, timeout_ms, [cb, key](const SockException &ex) { + if (ex) { lock_guard lck(s_ffmpegMapMtx); s_ffmpegMap.erase(key); } - cb(ex,key); + cb(ex, key); }); }; @@ -727,12 +730,15 @@ void installWebApi() { auto src_url = allArgs["src_url"]; auto dst_url = allArgs["dst_url"]; int timeout_ms = allArgs["timeout_ms"]; + auto enable_hls = allArgs["enable_hls"].as(); + auto enable_mp4 = allArgs["enable_mp4"].as(); - addFFmpegSource(src_url,dst_url,timeout_ms,[invoker,val,headerOut](const SockException &ex,const string &key){ - if(ex){ + addFFmpegSource(src_url, dst_url, timeout_ms, enable_hls, enable_mp4, + [invoker, val, headerOut](const SockException &ex, const string &key) { + if (ex) { const_cast(val)["code"] = API::OtherFailed; const_cast(val)["msg"] = ex.what(); - }else{ + } else { const_cast(val)["data"]["key"] = key; } invoker("200 OK", headerOut, val.toStyledString()); @@ -1084,6 +1090,8 @@ void installWebApi() { addFFmpegSource("http://hls-ott-zhibo.wasu.tv/live/272/index.m3u8",/** ffmpeg拉流支持任意编码格式任意协议 **/ dst_url, (1000 * timeout_sec) - 500, + false, + false, [invoker,val,headerOut](const SockException &ex,const string &key){ if(ex){ const_cast(val)["code"] = API::OtherFailed;